在工作中开发一个新查询时,我编写了它并在 SQL 查询分析器中对其进行了分析。该查询在没有任何表扫描的情况下执行得非常好,但是当我将它封装在存储过程中时,性能非常糟糕。当我查看执行计划时,我可以看到 SQL Server 选择了一个不同的计划,该计划使用表扫描而不是 TableB 上的索引搜索(我被迫稍微混淆表和列名,但没有任何查询逻辑已经改变)。
这是查询
SELECT
DATEADD(dd, 0, DATEDIFF(dd, 0, TableA.Created)) AS Day,
DATEPART(hh, TableA.Created) AS [Hour],
SUM(TableB.Quantity) AS Quantity,
SUM(TableB.Amount) AS Amount
FROM
TableA
INNER JOIN TableB ON TableA.BID = TableB.ID
WHERE
(TableA.ShopId = @ShopId)
GROUP BY
DATEADD(dd, 0, DATEDIFF(dd, 0, TableA.Created)),
DATEPART(hh, TableA.Created)
ORDER BY
DATEPART(hh, TableA.Created)
当我运行查询“原始”时,我得到以下跟踪统计信息
事件类持续时间 CPU 读取 写入 SQL:Stmt 已完成 75 41 7 0
当我使用以下命令将查询作为存储过程运行时
DECLARE @ShopId int
SELECT @ShopId = 1
EXEC spStats_GetSalesStatsByHour @ShopId
我得到以下跟踪统计信息
事件类持续时间 CPU 读取 写入 SQL:Stmt 已完成 222 10 48 0
如果我将查询存储在 nvarchar 中并像这样使用 sp_executesql 执行它(它的执行类似于 sproc),我也会得到相同的结果
DECLARE @SQL nvarchar(2000)
SET @SQL = 'SELECT DATEADD(dd, ...'
exec sp_executesql @SQL
除了上面的 select 语句,存储过程不包含任何内容。什么会导致 sql server 仅仅因为语句作为存储过程执行而选择较差的执行计划?
我们目前在SQL Server 2000上运行