【问题标题】:Stored procedure exeuction plan of SQL ServerSQL Server的存储过程执行计划
【发布时间】:2020-10-16 14:16:52
【问题描述】:

我知道 SQL Server 在第一次运行时会创建存储过程的执行计划。然后会一次又一次地被重用,直到它被重新编译。

如果有以下存储过程并且我第一次使用参数“A”执行该存储过程,其余查询(除“A”之外的其余参数)是否会因为执行计划仅适用于“一个'?

CREATE PROC SP_TEST 
    @FLAG NVARCHAR(5)
AS
BEGIN
    IF (@FLAG = 'A')
    BEGIN
        SELECT ... 
        FROM A_TABLE

        UPDATE ... 
        FROM A_TABLE

        INSERT ... 
        FROM A_TABLE
    END  -- IF (@FLAG = 'A')
    ELSE IF (@FLAG = 'B')
    BEGIN
        SELECT ... 
        FROM B_TABLE

        UPDATE ... 
        FROM B_TABLE

        INSERT ... 
        FROM B_TABLE
    END   -- ELSE IF (@FLAG = 'B')
    ELSE
    BEGIN
        SELECT ... 
        FROM TABLE

        UPDATE ... 
        FROM TABLE

        INSERT ... 
        FROM TABLE
    END   -- ELSE
END

【问题讨论】:

  • 建议你看看 Erland 对performance mysteries 的讨论。我真的很希望你不要写这样的程序。过程应该是具有特定目的的单个代码单元。由于许多原因,这种 方法并不是一个好的模式。
  • 谢谢!我只是想知道,因为我同时使用了 ot 数据库(sql-server,oracle)。但有时我可以看到 PL/SQL 在 Oracle 中包含很多带有“IF”的部分。这就是为什么我想在 sql-server 方面肯定地了解它。
  • 旁注:您应该为您的存储过程使用sp_ 前缀。微软有reserved that prefix for its own use (see Naming Stored Procedures),你确实会在未来某个时候冒着名称冲突的风险。 It's also bad for your stored procedure performance。最好只是简单地避免 sp_ 并使用其他东西作为前缀 - 或者根本不使用前缀!
  • 另外说存储过程有执行计划也不正确。存储过程中的每个语句都有自己的执行计划,因此在您的示例情况下,对于在运行时使用的每个 @@OPTIONS 组合,将有九个单独的计划(每个选择/更新/插入语句一个)。
  • 谢谢,如果您不介意,您能详细解释一下@@options 吗?其实我一看到这个就在MS doc上找到了,只是没完全看懂。

标签: sql-server stored-procedures sql-execution-plan sp


【解决方案1】:

有一种叫做参数嗅探的东西,如果您对特定列的数据有偏差(例如冰淇淋选择。很多人会选择香草,草莓、巧克力等的值将会减少)。如果第一个查询是针对 Strawberry,则计划将针对草莓。

CREATE NON CLUSTERED INDEX idx_Icecreamchoice on dbo.Employee(Icecreamchoice) 

--The below query might use bookmark lookup, which is fine, as there will be less IO

SELECT EmployeeName, ... FROM Employee WHERE IcecreamChoice = 'Strawberry'

但是,由于参数嗅探,下面的查询也会尝试使用书签查找,这会导致更多的IO,导致性能不佳。

SELECT EmployeeName, ... FROM Employee WHERE IcecreamChoice = 'Vannilla'

我们需要使用 RECOMPILE 选项来避免这些情况。我们也可以进行语句级别的重新编译。

SELECT EmployeeName, ... FROM Employee WHERE IcecreamChoice = 'Vannilla' option (recompile)

在您的问题中,由于您对标志有 IF ELSE 逻辑,因此不同的标志会有不同的路径,因此不会导致参数嗅探问题。他们正在访问不同的表集。

BEGIN
    IF (@FLAG = 'A') -- PATH 1
    BEGIN
        SELECT ... 
        FROM A_TABLE

        UPDATE ... 
        FROM A_TABLE

        INSERT ... 
        FROM A_TABLE
    END  -- IF (@FLAG = 'A')
    ELSE IF (@FLAG = 'B') -- PATH 2
    BEGIN
        SELECT ... 
        FROM B_TABLE

        UPDATE ... 
        FROM B_TABLE

        INSERT ... 
        FROM B_TABLE
    END   -- ELSE IF (@FLAG = 'B')
    ELSE  -- PATH 3
    BEGIN
        SELECT ... 
        FROM TABLE

        UPDATE ... 
        FROM TABLE

        INSERT ... 
        FROM TABLE
    END   -- ELSE

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-11
    • 2010-09-22
    • 2012-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-07
    相关资源
    最近更新 更多