SQL - 使用常量值与参数的任何性能差异?

时间:2016-02-25 12:22:03

标签: sql sql-server sql-server-2012

在有多个查询在where子句中运行(不同的)常量值时,与性能有关,而不是在顶部有一个带有声明参数的查询,而参数值是否在改变?

在where子句中使用常量值的示例查询:

select
*
from [table]
where [guid_field] = '00000000-0000-0000-000000000000' --value changes

使用声明的参数提出(改进?)查询:

declare @var uniqueidentifier = '00000000-0000-0000-000000000000' --value changes

select
*
from [table]
where [guid_field] = @var

有什么区别吗?我正在查看类似于上述两个查询的执行计划,我看不出任何区别。但是,我似乎记得,如果你在SQL语句中使用常量值,那么SQL服务器将不会重用相同的查询执行计划,或者那种导致性能更差的东西 - 但实际上是真的吗?

3 个答案:

答案 0 :(得分:2)

在此区分参数和变量很重要。参数传递给过程和函数,声明变量。

解决变量问题,这就是问题中的SQL所在,在编译临时批处理时,SQL Server会自己编译每个语句。 因此,当使用变量编译查询时,它不会返回检查任何赋值,因此它将编译针对未知变量优化的执行计划。 首次运行时,此执行计划将添加到计划缓存中,然后将来的执行可以,并将为所有变量值重用此缓存。

当您传递一个常量时,查询将根据该特定值进行编译,因此可以创建更优化的计划,但会增加重新编译的成本。

所以要专门回答你的问题:

  

但是,我似乎记得,如果你在SQL语句中使用常量值,那么SQL服务器将不会重用相同的查询执行计划,或者那种导致性能更差的东西 - 但实际上是真的吗?

是的,同一个计划不能重复用于不同的常量值,但这并不一定会导致性能下降。有可能可以将更合适的计划用于该特定常量(例如,在稀疏数据的索引扫描上选择书签查找),并且此查询计划更改可能超过重新编译的成本。因此,关于SQL性能问题的情况几乎总是如此。答案是取决于

对于参数,默认行为是基于何时首次执行过程或函数时使用的参数来编译执行计划。

我之前已经通过实例更详细地回答了类似的问题,这些例子涵盖了上述的很多内容,因此我不会重复其中的各个方面,而是将链接问题:

答案 1 :(得分:1)

你的问题涉及很多事情,而且都与统计数据有关。

SQL编译甚至Adhoc查询的执行计划,并将它们存储在计划缓存中以供重用,如果它们被认为是安全的。

var a = +$('.container1 .tooltip span').text();
var b = +$('.container2 .tooltip span').text();

console.log(a - b);

先问: 我们每次都尝试不同的文字,所以如果它认为安全,sql会保存计划。你可以看到第二个查询估计与升4相同,因为SQL保存了4的计划

select * into test from sys.objects

select schema_id,count(*) from test
group by schema_id


--schema_id 1 has 15
--4 has 44 rows

输出

enter image description here

--lets clear cache first--not for prod
dbcc freeproccache

select * from test
where schema_id=4

<强>输出:

enter image description here

第二问:
将局部变量作为参数传递,让我们使用相同的值4

select * from test where 
 schema_id=1

正如您在下面的截图中看到的那样,使用局部变量估计的一些粗略的29.5行与统计数据有关。

输出

enter image description here

总而言之,统计数据在选择查询计划(嵌套循环或执行扫描或搜索)时至关重要 从示例中,您可以看到每种方法的估算方法有何不同。另外,从计划缓存膨胀角度来看

您可能也想知道,如果我传递了许多adhoc查询会发生什么,因为即使空间有变化,SQL也会为同一查询生成新计划,下面是可以帮助您的链接

进一步阅读:
http://www.sqlskills.com/blogs/kimberly/plan-cache-adhoc-workloads-and-clearing-the-single-use-plan-cache-bloat/
http://sqlperformance.com/2012/11/t-sql-queries/ten-common-threats-to-execution-plan-quality

答案 2 :(得分:0)

首先,请注意局部变量与参数不同。

假设列已编制索引或具有统计信息,SQL Server使用统计信息直方图根据提供的常量值收集估计符合条件的行计数。如果查询是微不足道的,那么查询也将被自动参数化和缓存(无论值如何都产生相同的计划),以便后续执行可以避免查询编译成本。

参数化查询还使用统计直方图和最初提供的参数值生成计划。该计划被缓存并重新用于后续执行,无论它是否是微不足道的。

使用局部变量,SQL Server使用整体统计基数来生成计划,因为实际值在编译时是未知的。对于某些值,此计划可能有用,但当查询不是微不足道时,对其他值可能不是最理想的。