SQL Server - якщо логіка в збереженій процедурі та кеш плану


15

Стандарт SQL Server 2012 та 2016:

Якщо я вкладаю if-elseлогіку в збережену процедуру для виконання однієї з двох гілок коду, залежно від значення параметра, чи двигун кешує останню версію?

І якщо при наступному виконанні значення параметра зміниться, чи буде він перекомпільований і повторно кешований збережена процедура , оскільки повинна бути виконана інша гілка коду? (Цей запит досить дорого складати.)

Відповіді:


27

Стандарт SQL Server 2012 та 2016: Якщо я вкладаю логіку if-else у збережену процедуру для виконання однієї з двох гілок коду, залежно від значення параметра, чи двигун кешує останню версію?

Ні, він кешує всі версії. А точніше, він кешує одну версію з усіма дослідженими шляхами , складеними з пропущеними змінними.

Ось коротка демонстрація за допомогою бази даних переповнення стека.

Створіть індекс:

CREATE INDEX ix_yourmom ON dbo.Users (Reputation) INCLUDE (Id, DisplayName);
GO 

Створіть збережену процедуру з підказкою індексу, яка вказує на індекс, який не існує, у розгалуженому коді.

CREATE OR ALTER PROCEDURE dbo.YourMom (@Reputation INT)
AS 
BEGIN

    IF @Reputation = 1
    BEGIN
        SELECT u.Id, u.DisplayName, u.Reputation
        FROM dbo.Users AS u WITH (INDEX = PK_Users_Id)
        WHERE u.Reputation = @Reputation;
    END;

    IF @Reputation > 1
    BEGIN
        SELECT u.Id, u.DisplayName, u.Reputation
        FROM dbo.Users AS u WITH (INDEX = ix_yourdad)
        WHERE u.Reputation = @Reputation;

    END;

END;

Якщо я виконую цю збережену програму в пошуку Reputation = 1, я отримую помилку.

EXEC dbo.YourMom @Reputation = 1;

Пост. 308, Рівень 16, Стан 1, Процедура YourMom, Рядок 14 [Початковий рядок пакету 32] Індекс 'ix_yourdad' у таблиці 'dbo.Users' (вказаний у пункті FROM) не існує.

Якщо ми виправимо ім'я індексу та повторно виконаємо запит, кешований план виглядає приблизно так:

Горіхи

Всередині XML буде два посилання на @Reputationзмінну.

<ColumnReference Column="@Reputation" ParameterDataType="int" ParameterCompiledValue="(1)" />

Трохи простішим тестом було б просто отримати орієнтовний план для збереженого процесора. Ви можете побачити оптимізатор, що вивчає обидва контури:

Горіхи

І якщо при наступному виконанні значення параметра зміниться, чи буде він перекомпільований і повторно кешований збережена процедура, тому що повинна бути виконана інша гілка коду? (Цей запит складати досить дорого.) Дякую.

Ні, воно збереже значення часу виконання першої компіляції.

Якщо ми повторно виконаємо з іншим @Reputation:

EXEC dbo.YourMom @Reputation = 2;

З фактичного плану :

<ColumnReference Column="@Reputation" ParameterDataType="int" ParameterCompiledValue="(1)" ParameterRuntimeValue="(2)" />

У нас все ще є зібране значення 1, але зараз значення часу виконання 2.

У кеш-плані плану, який ви можете перевірити за допомогою безкоштовного інструменту, такого, як розробляє моя компанія, sp_BlitzCache :

Горіхи

Збережена процедура викликалася двічі, і кожне висловлення в ній було викликано один раз.

То що ми маємо? Один кешований план для обох запитів у збереженій процедурі.

Якщо вам потрібна така розгалужена логіка, вам доведеться зателефонувати до збережених процедур:

CREATE OR ALTER PROCEDURE dbo.YourMom (@Reputation INT)
AS 
BEGIN

    IF @Reputation = 1
    BEGIN

        EXEC dbo.Reputation1Query;

    END;

    IF @Reputation > 1
    BEGIN

        EXEC dbo.ReputationGreaterThan1Query;

    END;

END;

Або динамічний SQL:

DECLARE @sql NVARCHAR(MAX) = N''

SET @sql +=
N'
SELECT u.Id, u.DisplayName, u.Reputation
        FROM dbo.Users AS u '
IF @Reputation = 1
BEGIN
    SET @sql += N' (INDEX = PK_Users_Id)
        WHERE u.Reputation = @Reputation;'
END;


IF @Reputation > 1 
BEGIN

SET @sql += ' WITH (INDEX = ix_yourmom)
        WHERE u.Reputation = @Reputation;'

END;


EXEC sys.sp_executesql @sql;

Сподіваюся, це допомагає!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.