sql - 直接执行语句和从存储过程执行语句时的执行计划不同

标签 sql sql-server tsql stored-procedures sql-execution-plan

在工作中开发新查询时,我编写了它并在 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)

当我运行查询“raw”时,我得到以下跟踪统计信息

Event Class         Duration  CPU  Reads Writes
SQL:StmtCompleted   75        41      7      0

And when I run the query as a stored proc using the following command

DECLARE @ShopId int
SELECT @ShopId = 1
EXEC spStats_GetSalesStatsByHour @ShopId

我得到以下跟踪统计信息

Event Class         Duration  CPU  Reads Writes
SQL:StmtCompleted   222       10     48      0

I also get the same result if I store the query in an nvarchar and execute it using sp_executesql like this (it performs like the sproc)

DECLARE @SQL nvarchar(2000)
SET @SQL = 'SELECT DATEADD(dd, ...'
exec sp_executesql @SQL

除了上面的 select 语句之外,存储过程不包含任何内容。什么会导致 sql server 仅因为该语句作为存储过程执行而选择较差的执行计划?

我们目前在 SQL Server 2000 上运行

最佳答案

这通常与参数嗅探有关。处理起来可能会非常令人沮丧。有时可以通过重新编译存储过程来解决,有时甚至可以在存储过程中使用重复变量,如下所示:

alter procedure p_myproc (@p1 int) as
declare @p1_copy int;
set @p1_copy = @p1;

然后在查询中使用@p1_copy。看起来很荒谬,但确实有效。

查看我最近关于同一主题的问题:

Why does the SqlServer optimizer get so confused with parameters?

关于sql - 直接执行语句和从存储过程执行语句时的执行计划不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/421275/

相关文章:

sql - 列存储索引的正确使用

基于日期的 SQL Case 语句

sql - 计算中位数移动平均单位成本时使用 Over(Partition By)

c# - 如何从数据库中获取 SQL CLR 函数的定义

sql - 合并以更新所有目标表列

sql - 如何计算与唯一 ID 相关的值已更改的次数?

sql - 是否可以从 SQL Server 调用 Web 服务?

java - 在 java 存储过程中创建 java.sql.blob 实例

php - 计算 laravel 中查询返回的行数

sql - Google BigQuery SQL 用于对各个列求和