我有一个参数化查询,看起来像(使用?作为应用程序参数):
SELECT * FROM tbl WHERE tbl_id = ?
添加变量的性能影响如下:
DECLARE @id INT = ?;
SELECT * FROM tbl WHERE tbl_id = @id
我试图调查自己,但除了查询计划在第一次运行查询时需要稍微长时间编译时,我没有运气。
第二种方法的一个优点是减少了SQL将存储的计划数量。在第一个版本中,它将为每种数据类型(tinyint,smallint,int和bigint)创建不同的计划
这假设是一个特别声明。
如果它在存储过程中 - 你可能会遇到如上所述的p-sniffing。
你可以尝试添加
OPTION ( OPTIMIZE FOR (@id = [some good value]))
选择以查看是否有帮助 - 但通常不认为将查询与值相结合是一种好习惯。
如果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就像以前一样:它估计了一堆可能的执行计划的成本,考虑了估计的基数,选择最有效的一个并将其缓存以供以后重用。同样,这种方法大部分时间都有效。但是,如果使用一个参数值执行查询,该参数值的基数与均值基本不同,则执行计划的效率可能非常低。
当所有值具有相同的基数时,它们具有平均基数,因此参数和变量之间没有区别。这是唯一值的情况,因此当值是唯一的时,没有区别。