Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 为什么用局部变量替换参数会加快查询速度_Sql_Sql Server_Tsql - Fatal编程技术网

Sql 为什么用局部变量替换参数会加快查询速度

Sql 为什么用局部变量替换参数会加快查询速度,sql,sql-server,tsql,Sql,Sql Server,Tsql,我有一个查询,它有两个日期参数,例如: @startDate DATE, @endDate DATE 在开发存储过程时,它在

我有一个查询,它有两个日期参数,例如:

@startDate DATE,
@endDate DATE
在开发存储过程时,它在<1秒时非常棒。作为一个孩子,我将它移动到一个存储过程中,当我再次运行它时,准确地说,运行2需要几分钟

我之前遇到过这种情况,我认为这是某种异常现象,当时我没有追查,所以我尝试了最后一种有效的破解方法:

DECLARE @sDate DATE = CAST(@startDate AS DATE);
DECLARE @eDate DATE = CAST(@endDate AS DATE);
果然,返回时间小于1s

我已经想尽一切办法来解决这个问题,但似乎没有任何效果。我在任何地方都找不到改变任何事情的差异。这些值是完全相同的,不管我尝试了多少种不同的方式来分割它

我也尝试过:

SET @startDate = CAST(@startDate AS DATE);
SET @startDate = CONVERT(date, @startDate, 101)
我尝试过使用父存储过程中的任何方法重新声明它们

只有在子存储过程中重新声明变量时,它才起作用

那么,为什么重新声明同一类型的变量会导致性能上的巨大差异呢

更新-这是参数嗅探 我最初并不这么认为,但所有证据都表明事实确实如此,尽管我无法用正常的方法来修复它,而这些方法通常要么有效,要么有助于识别它。除了用一个局部变量替换它之外,在下面所有海报的帮助下,它将表明它必须是参数嗅探

第一次更新

我不认为这是参数嗅探——这是我的第一个想法。这就是我所做的测试:

已更改的参数添加/删除 向查询中添加了其他条件 添加了选项重新编译 启用ARITHABORT 删除/创建旧索引和新索引
上述更改对查询没有影响。

这是一种参数嗅探解决方案。我建议阅读:

参数和变量

考虑Northwind数据库中的Orders表,以及以下三个过程:

在第一个过程中,日期是常量,这意味着SQL Server只需要精确地考虑这种情况。它查询Orders表的统计信息,这表明在第三个千年中没有OrderDate行。Northwind数据库中的所有订单都是从1996年到1998年。由于统计信息是统计信息,SQL Server无法确定查询是否将不返回任何行,为什么它会估计一行

对于List_orders_2,查询针对的是一个变量,或者更准确地说是一个参数。执行优化时,SQL Server知道已使用值2000-01-01调用该过程。由于它不执行任何流分析,因此无法确定在执行查询时参数是否具有此值。尽管如此,它还是使用输入值得出一个估计值,这与List_orders_1相同:一行。这种在优化存储过程时查看输入参数值的策略称为参数嗅探

在最后一个过程中,情况完全不同。输入值被复制到一个局部变量,但是当SQLServer构建计划时,它不了解这一点,并且对自己说我不知道这个变量的值是什么

要点

在本节中,我们学到了三件非常重要的事情:

-常量是常量,当查询包含常量时,SQL Server可以完全信任地使用该常量的值,甚至可以通过这些快捷方式完全不访问表,前提是它可以从约束推断不返回任何行

-对于参数,SQL Server不知道运行时值,但在编译查询时会嗅探输入值

-对于局部变量,SQL Server完全不知道运行时值,并应用标准假设。哪些假设取决于运算符,以及可以从唯一索引的存在中推断出什么


第二篇伟大的文章,因为它改变了执行计划。那是你必须去看的地方。也许这也导致了查询被重新编译。您是否运行了此proc/query 10多次并获得了max/min/avg运行时?请查看此链接以了解有关如何改进问题的更多信息。这是最大的问题。你说这不是参数嗅探和多次阅读你的问题也许不是…但我不相信这一点。对我来说,这听起来真是经典的嗅探。没有人能回答这个问题的原因是因为你没有提供任何实际的细节。我们不知道您的表格设计是什么,也不知道相关程序在做什么。遵循GameIswar提供的链接,然后发布一些真实的细节。如果没有这些,我们只能猜测。是的,如果你用局部变量替换参数来修复它,那就是参数嗅探。你排除它的理由没有一个像这一个理由那么有力。如果不是参数嗅探,用局部变量替换参数是不可行的
不过,我已经尝试了所有已知的技巧来打破这个局面,但一切都没有改变。我用我试过的方法编辑了这个问题。也许我错过了一个确保它是或不是参数嗅探的技巧。我通常通过重新定义参数来修复参数嗅探,所以我认为你是100%正确的。
CREATE PROCEDURE List_orders_1 AS
   SELECT * FROM Orders WHERE OrderDate > '20000101'
go
CREATE PROCEDURE List_orders_2 @fromdate datetime AS
   SELECT * FROM Orders WHERE OrderDate > @fromdate
go
CREATE PROCEDURE List_orders_3 @fromdate datetime AS
   DECLARE @fromdate_copy datetime
   SELECT @fromdate_copy = @fromdate
   SELECT * FROM Orders WHERE OrderDate > @fromdate_copy
go