Няма да се опитвам да обяснявам пълните подробности за надушването на параметри, но накратко, не, не винаги помощ (и може да попречи).
Представете си таблица (T) с първичен ключ и индексирана колона с дата (A), в таблицата има 1000 реда, 400 имат същата стойност на A (да кажем днес 20130122), останалите 600 реда са следващите 600 дни , така че само 1 запис на дата.
Тази заявка:
SELECT *
FROM T
WHERE A = '20130122';
Ще даде различен план за изпълнение на:
SELECT *
FROM T
WHERE A = '20130123';
Тъй като статистиката ще покаже, че за първите 400 от 1000 реда ще бъдат върнати, оптимизаторът трябва да разпознае, че сканирането на таблица ще бъде по-ефективно от търсенето в отметка, докато второто ще даде само 1 ред, така че търсенето в отметка ще бъде много по-ефективен.
Сега да се върнем към въпроса ви, ако сме направили това процедура:
CREATE PROCEDURE dbo.GetFromT @Param DATE
AS
SELECT *
FROM T
WHERE A = @Param
След това стартирайте
EXECUTE dbo.GetFromT '20130122'; --400 rows
Планът на заявката със сканирането на таблицата ще бъде използван, ако първия път, когато го стартирате, използвате '20130123' като параметър, той ще съхрани плана за търсене на отметки. Докато процедурата не бъде прекомпилирана, планът ще остане същият. Правете нещо подобно:
CREATE PROCEDURE dbo.GetFromT @Param VARCHAR(5)
AS
DECLARE @Param2 VARCHAR(5) = @Param;
SELECT *
FROM T
WHERE A = @Param2
След това се изпълнява това:
EXECUTE dbo.GetFromT '20130122';
Докато процедурата се компилира наведнъж, тя не протича правилно, така че планът на заявката, създаден при първата компилация, няма представа, че @Param2 ще стане същото като @param, така че оптимизаторът (без да знае колко реда трябва да очаквам) ще приеме, че ще бъдат върнати 300 (30%), тъй като това ще счита сканирането на таблица за по-ефективно от търсенето в отметка. Ако изпълните същата процедура с „20130123“ като параметър, тя ще доведе до същия план (независимо с какъв параметър е била извикана за първи път), тъй като статистиката не може да се използва за неизвестна стойност. Така че изпълнението на тази процедура за „20130122“ би било по-ефективно, но за всички други стойности би било по-малко ефективно, отколкото без локални параметри (ако приемем, че процедурата без локални параметри е била извикана първо с нещо друго освен „20130122“)
Някои заявки за демонстриране, за да можете сами да видите плановете за изпълнение
Създаване на схема и примерни данни
CREATE TABLE T (ID INT IDENTITY(1, 1) PRIMARY KEY, A DATE NOT NULL, B INT,C INT, D INT, E INT);
CREATE NONCLUSTERED INDEX IX_T ON T (A);
INSERT T (A, B, C, D, E)
SELECT TOP 400 CAST('20130122' AS DATE), number, 2, 3, 4
FROM Master..spt_values
WHERE type = 'P'
UNION ALL
SELECT TOP 600 DATEADD(DAY, number, CAST('20130122' AS DATE)), number, 2, 3, 4
FROM Master..spt_values
WHERE Type = 'P';
GO
CREATE PROCEDURE dbo.GetFromT @Param DATE
AS
SELECT *
FROM T
WHERE A = @Param
GO
CREATE PROCEDURE dbo.GetFromT2 @Param DATE
AS
DECLARE @Param2 DATE = @Param;
SELECT *
FROM T
WHERE A = @Param2
GO
Изпълнение на процедури (показващ действителен план за изпълнение):
EXECUTE GetFromT '20130122';
EXECUTE GetFromT '20130123';
EXECUTE GetFromT2 '20130122';
EXECUTE GetFromT2 '20130123';
GO
EXECUTE SP_RECOMPILE GetFromT;
EXECUTE SP_RECOMPILE GetFromT2;
GO
EXECUTE GetFromT '20130123';
EXECUTE GetFromT '20130122';
EXECUTE GetFromT2 '20130123';
EXECUTE GetFromT2 '20130122';
Ще видите това първия път GetFromT
се компилира, използва сканиране на таблица и запазва това, когато се изпълнява с параметъра „20130122“, GetFromT2
също използва сканиране на таблица и запазва плана за '20130122'.
След като процедурите са зададени за повторно компилиране и стартиране отново (забележете в различен ред), GetFromT
използва цикъл на отметка и запазва плана за „20130122“, въпреки че преди това е преценил, че сканирането на таблица е по-подходящ план. GetFromT2
не е засегнат от поръчката и има същия план като преди повторното изпълнение.
И така, в обобщение, зависи от разпределението на вашите данни и вашите индекси, вашата честота на повторно компилиране и малко късмет дали дадена процедура ще има полза от използването на локални променливи. Със сигурност не винаги помощ.
Надяваме се, че съм хвърлил малко светлина върху ефекта от използването на локални параметри, планове за изпълнение и компилиране на съхранени процедури. Ако съм се провалил напълно или съм пропуснал ключова точка, тук може да се намери много по-задълбочено обяснение:
http://www.sommarskog.se/query-plan-mysteries.html