我有一个参数化查询,看起来像(?是应用程序参数):
SELECT * FROM tbl WHERE tbl_id = ?
添加这样的变量对性能有何影响?
DECLARE @id INT = ?;
SELECT * FROM tbl WHERE tbl_id = @id
我已经尝试过调查自己,但是除了查询计划第一次运行时需要花费更长的时间来编译之外,没有其他运气。
答案 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)
),但是我发现这通常无济于事,并且不会产生与上述技巧相同的效果。我无法调查为什么它们不同的细节,但是我经历了“优化未知”的问题,就像使用局部变量代替变量一样。