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
我知道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