【问题标题】:Impact of variables in a paramatized SQL query参数化 SQL 查询中变量的影响
【发布时间】:2018-09-12 04:41:06
【问题描述】:

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

SELECT * FROM tbl WHERE tbl_id = ?

像这样添加变量对性能有何影响:

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

我曾尝试调查自己,但除了在第一次运行查询时编译查询计划需要稍长一点的时间之外没有运气。

【问题讨论】:

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


【解决方案1】:

如果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 做和以前一样的事情:它估计一堆可能的执行计划的成本,考虑到估计的基数,选择最有效的一个并将其缓存以供以后重用。同样,这种方法在大多数情况下都有效。但是,如果您使用一个与平均值有很大不同基数的参数值执行查询,则执行计划可能会非常低效。

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

【讨论】:

    【解决方案2】:

    第二种方法的一个优点是减少了 SQL 将存储的计划数量。 在第一个版本中,它将为每种数据类型(tinyint、smallint、int 和 bigint)创建不同的计划

    假设它是一个临时声明。

    如果它在存储过程中 - 您可能会遇到上面提到的 p-sniffing。

    你可以试试添加

    OPTION ( OPTIMIZE FOR (@id = [some good value]))
    

    到 select 看看是否有帮助 - 但通常不认为将查询与值结合起来的好习惯。

    【讨论】:

    • 如果您在客户端应用程序中声明参数数据类型,为什么 SQL Server 会为每种数据类型创建计划?
    • 好问题 - 我不记得确切的细节,但我在去年的 SQL 星期六会议上从 Kimberly Tripp 那里听到了这个消息,所以我很确定它是正确的!本质上,为每个不同类型的参数值创建(并保留)一个单独的计划
    【解决方案3】:

    我不确定这是否有帮助,但我必须考虑到我编写的许多存储过程的参数嗅探。为此,我创建了局部变量,将它们设置为参数值,然后在存储过程中使用局部变量。如果查看存储的执行计划,您会发现这会阻止在计划中使用参数值。

    这就是我的工作:

    CREATE PROCEDURE dbo.Test ( @var int )
    AS
    DECLARE 
        @_var int
    SELECT 
        @_var = @var
    
    SELECT * 
    FROM dbo.SomeTable 
    WHERE
        Id = @_var
    

    我这样做主要是为了 SSRS。例如,我有一个查询/存储过程返回

    还有优化特定值的选项(例如OPTION (OPTIMIZE @var FOR UNKNOWN)),但我发现这通常对我没有帮助,并且不会产生与上述技巧相同的效果。我无法调查细节以了解它们为何不同,但我体验过 OPTIMIZE FOR UNKNOWN 并没有帮助,而使用局部变量代替变量则有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-24
      • 1970-01-01
      • 2012-06-09
      • 1970-01-01
      • 1970-01-01
      • 2014-07-22
      • 1970-01-01
      相关资源
      最近更新 更多