我知道SQL Server在第一次运行时会创建存储过程的执行计划。然后会一次又一次地重复使用,直到重新编译为止。
如果有以下存储过程,并且我第一次使用参数“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'
我们需要使用 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