变量对参数化SQL查询的影响

时间:2018-09-12 04:41:06

标签: sql sql-server tsql sql-execution-plan

我有一个参数化查询,看起来像(?是应用程序参数):

SELECT * FROM tbl WHERE tbl_id = ?

添加这样的变量对性能有何影响?

DECLARE @id INT = ?;
SELECT * FROM tbl WHERE tbl_id = @id

我已经尝试过调查自己,但是除了查询计划第一次运行时需要花费更长的时间来编译之外,没有其他运气。

2 个答案:

答案 0 :(得分:0)

如果tbl_id是唯一的,则没有任何区别。我正试图解释原因。

SQL Server通常可以使用许多不同的执行计划来解决查询。 SQL Server必须选择一个。它会尝试找到最有效的方法,而无需付出过多的努力。 SQL Server选择一个计划后,通常会对其进行缓存以备后用。基数在执行计划的效率中起着关键作用,即tbl上有多少行,给定值为tbl_id? SQL Server存储列值频率统计信息以估计基数。

首先,假设tbl_id不是唯一的并且具有不均匀的分布。

在第一种情况下,我们有tbl_id = ?。让我们找出其基数。我们需要弄清楚的第一件事是知道参数?的值。不知道吗并不是的。第一次执行查询时,我们有一个值。 SQL Server取这个值,转到存储的统计信息中,并为该特定值估计基本值,它考虑到估计的基数来估计一堆可能的执行计划的成本,选择效率最高的一个并将其缓存以备后用。这种方法大多数时候都有效。但是,如果以后使用基数差异很大的其他参数值执行查询,则缓存的执行计划可能效率很低。

在第二种情况下,我们将tbl_id = @id作为@id在查询中声明的变量,它不是查询参数。 @id的值是多少? SQL Server将其视为未知值。 SQL Server从存储的统计信息中获得平均频率的峰值,作为未知值的估计基数。然后,SQL Server会像以前一样进行操作:考虑到估计的基数,它估计一堆可能的执行计划的成本,选择效率最高的计划并将其缓存以备后用。同样,这种方法在大多数时间都有效。但是,如果使用一个基数与平均值有很大不同的参数值执行查询,则执行计划可能效率很低。

当所有值具有相同的基数时,它们具有均值基数,因此参数和变量之间没有区别。唯一值就是这种情况,因此,值唯一时没有区别。

答案 1 :(得分:0)

我不确定这是否有帮助,但是我必须考虑我编写的许多存储过程的参数嗅探。我通过创建局部变量,将其设置为参数值,然后在存储过程中使用局部变量来做到这一点。如果查看存储的执行计划,可以看到这会阻止参数值在计划中使用。

这就是我的工作

CREATE PROCEDURE dbo.Test ( @var int )
AS
DECLARE 
    @_var int
SELECT 
    @_var = @var

SELECT * 
FROM dbo.SomeTable 
WHERE
    Id = @_var

我主要是针对SSRS执行此操作。我有一个查询/存储过程返回时间少于1秒,但是例如报告需要几分钟。上面的技巧解决了这个问题。

还有一些用于优化特定值的选项(例如OPTION (OPTIMIZE @var FOR UNKNOWN)),但是我发现这通常无济于事,并且不会产生与上述技巧相同的效果。我无法调查为什么它们不同的细节,但是我经历了“优化未知”的问题,就像使用局部变量代替变量一样。