在优化一些存储过程时,我与 DBA 坐下来讨论了一些具有高阻塞和/或高读/写活动的存储过程。
DBA 提到的一件事是我应该TABLE
在存储过程的顶部声明所有变量(尤其是变量)以避免重新编译。
这是我第一次听说这个并且在重新访问我们拥有的所有不同的存储过程之前正在寻找一些确认。他称其为“延迟查看代码”,并且重新编译锁定了导致阻塞的模式。
将所有变量声明移动到存储过程的顶部是否会减少重新编译?
在优化一些存储过程时,我与 DBA 坐下来讨论了一些具有高阻塞和/或高读/写活动的存储过程。
DBA 提到的一件事是我应该TABLE
在存储过程的顶部声明所有变量(尤其是变量)以避免重新编译。
这是我第一次听说这个并且在重新访问我们拥有的所有不同的存储过程之前正在寻找一些确认。他称其为“延迟查看代码”,并且重新编译锁定了导致阻塞的模式。
将所有变量声明移动到存储过程的顶部是否会减少重新编译?
不。
这要么在很久以前是正确的(现在不再是,至少从 SQL Server 2000 开始),或者它从来都不是正确的,您的 DBA 只是将他的建议与以下建议混淆了:
您可以在此页面上找到有关此建议背后原因的另一种解释。
如果我们查看这个 Microsoft KB,我们会发现存储过程重新编译的原因可能是以下之一(SQL Server 2005+):
声明一个变量——甚至是一个表变量(即
@table_variable
)——显然不能触发任何这些事件,因为声明一个变量不算作 DDL。变量(甚至是表变量)是专门用于 T-SQL 编程的临时对象。这就是为什么表变量没有统计信息并且不受事务约束的原因。 声明一个变量(表与否)不能触发 proc 重新编译。#temp_table
然而,创建临时表(即)或索引是影响数据库物理定义的 DDL。临时表和索引是具有统计信息和事务控制的“真实”对象,因此创建它们可能会触发上面列表中的任何事件 1、2 或 5,从而触发 proc 重新编译。它不应该产生影响或减少编译锁或导致较少的重新编译来声明堆栈中途或顶部的变量。为了可读性,我经常在顶部这样做。
为了解决问题的“我的 DBA 在想什么”部分,我唯一能想到的(除了尼克的观点,他们正在考虑过去的情况)可能是他们在谈论参数嗅探(参见选项 2 在此链接上的简单谈话)
关于您的阻塞 --> 如果您看到真正的阻塞,那不是您的 DBA 最有可能谈论的编译锁争用类型。虽然确实有某些事情会影响这一点(例如,不是模式限定表,不是模式限定您的存储过程调用),但这肯定不是您的高读取的原因,也可能不是您阻塞的原因。你绝对应该尽你所能避免这些编译锁。但我会将调整和优化其余存储过程代码视为比担心变量在哪里更重要的任务。如果您想在此处验证您没有遇到问题,还可以阅读如何识别和解决编译锁。
发布这些之前/之后的示例,我们将在这里看到 DBA 的驱动力。