SQL 服务器的存储过程执行计划

Stored procedure exeuction plan of SQL Server

我知道SQL服务器在第一次运行时会创建一个存储过程的执行计划。然后会被反复使用,直到重新编译。

如果有以下存储过程并且我第一次使用参数 'A' 执行它,那么其余查询(除 '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

有一种称为参数嗅探的东西,如果您对特定列的数据进行了倾斜(例如冰淇淋选择。许多人会选择 Vannila,草莓、巧克力等的值数量就会减少)。如果第一个查询是草莓,计划将为草莓准备。

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'

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

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