Sql server Sql Server如何为存储过程中的逻辑流编译执行计划?
我需要使用同一个查询两次,但where子句略有不同。我想知道如果用一个位值简单地调用同一个存储过程,并有一个if。。。其他的语句,决定要比较的字段 或者我应该创建两个存储过程,并根据应用程序中的逻辑调用每个过程 我想更详细地了解这一点,以便正确理解。 如何为此编制执行计划?是否每个IF中的每个代码块都有一个。。。还有Sql server Sql Server如何为存储过程中的逻辑流编译执行计划?,sql-server,Sql Server,我需要使用同一个查询两次,但where子句略有不同。我想知道如果用一个位值简单地调用同一个存储过程,并有一个if。。。其他的语句,决定要比较的字段 或者我应该创建两个存储过程,并根据应用程序中的逻辑调用每个过程 我想更详细地了解这一点,以便正确理解。 如何为此编制执行计划?是否每个IF中的每个代码块都有一个。。。还有 还是将其编译为一个大的执行计划?它使用传递到过程中的参数的初始值编译一次。尽管有些语句可能需要延迟编译,在这种情况下,最终编译时,它们将使用任何参数值进行编译 您可以从下面的运行和
还是将其编译为一个大的执行计划?它使用传递到过程中的参数的初始值编译一次。尽管有些语句可能需要延迟编译,在这种情况下,最终编译时,它们将使用任何参数值进行编译 您可以从下面的运行和查看实际执行计划中看到这一点
CREATE TABLE T
(
C INT
)
INSERT INTO T
SELECT 1 AS C
UNION ALL
SELECT TOP (1000) 2
FROM master..spt_values
UNION ALL
SELECT TOP (1000) 3
FROM master..spt_values
GO
CREATE PROC P @C INT
AS
IF @C = 1
BEGIN
SELECT '1'
FROM T
WHERE C = @C
END
ELSE IF @C = 2
BEGIN
SELECT '2'
FROM T
WHERE C = @C
END
ELSE IF @C = 3
BEGIN
CREATE TABLE #T
(
X INT
)
INSERT INTO #T
VALUES (1)
SELECT '3'
FROM T,
#T
WHERE C = @C
END
GO
EXEC P 1
EXEC P 2
EXEC P 3
DROP PROC P
DROP TABLE T
运行
2
案例将来自T
的估计行数显示为1
而不是1000
,因为该语句是根据1
传入的初始参数值编译的。运行3
案例给出了1000
的准确估计计数,因为对(尚未创建)临时表的引用意味着该语句受到延迟编译的影响。您应该关心正在缓存的执行计划
Martin给出了一个很好的例子,说明计划是缓存的,并且在第一次执行时将针对逻辑的某个分支进行优化。
在第一次执行之后,即使您使用不同的参数调用存储过程(存储过程),导致您的执行流选择另一个分支,也会重用该计划。
这非常糟糕,会影响性能。我见过这种情况很多次,要找到根本原因需要一段时间
这背后的原因被称为“参数嗅探”,它非常值得研究
一个常见的建议解决方案(我不建议这样做)是将您的存储过程分成几个小部分。
如果在存储过程中调用存储过程,则该内部存储过程将获得针对传递给它的参数优化的执行计划
在没有充分理由(模块化是一个很好的理由)的情况下,将一个存储过程拆分为几个较小的存储过程是一个丑陋的解决方法。Martin表明,通过对模式进行更改,可以重新编译语句。
我会在语句末尾使用选项(重新编译)。这将指示优化器在考虑所有变量的当前值的情况下重新编译语句:不仅考虑参数,还考虑局部变量,这会区分好的计划和坏的计划
回到您的问题,即根据参数使用不同的where子句构造查询。我将使用以下模式:
WHERE
(@parameter1 is null or col1 = @parameter1 )
AND
(@parameter2 is null or col2 = @parameter2 )
...
OPTION (RECOMPILE)
不利的一面是,该语句的执行计划从未被缓存(但它不会影响到语句的缓存),如果存储过程被多次执行,这可能会产生影响,因为现在应该考虑编译时间。使用生产质量数据执行测试将为您提供问题与否的答案
这样做的好处是,您可以编写可读且优雅的存储过程,而不会让优化器出错
要记住的另一个选项是,您可以在存储过程级别(与语句级别相反)禁用执行计划缓存,该级别粒度较小,更重要的是,在优化时不会考虑局部变量的值
更多信息请访问
http://sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/如果……否则……(或
案例
)具体包含什么?在某些情况下,将条件抽象为参数可能更有效。每个进程有一个执行计划,因此条件逻辑可能会导致性能不均衡。