Чи кешує SQL Server результат функції багатозначних табличних значень?


22

Функція з табличним значенням з декількома операторами повертає свій результат у змінну таблиці.

Ці результати коли-небудь повторно використовуються, або функція завжди повністю оцінюється кожного разу, коли вона викликається?

Відповіді:


23

Результати функції з багатовикладною таблицею (msTVF) ніколи не кешуються та не використовуються повторно через оператори (або з'єднання), але є кілька способів, щоб результат MSTVF міг повторно використовуватись у межах одного оператора. У цій мірі, msTVF не обов'язково повторно заселяється кожного разу, коли він викликається.

Приклад msTVF

Цей (навмисно неефективний) msTVF повертає заданий діапазон цілих чисел із часовою позначкою на кожен рядок:

IF OBJECT_ID(N'dbo.IntegerRange', 'TF') IS NOT NULL
    DROP FUNCTION dbo.IntegerRange;
GO
CREATE FUNCTION dbo.IntegerRange (@From integer, @To integer)
RETURNS @T table 
(
    n integer PRIMARY KEY, 
    ts datetime DEFAULT CURRENT_TIMESTAMP
)
WITH SCHEMABINDING
AS
BEGIN
    WHILE @From <= @To
    BEGIN
        INSERT @T (n)
        VALUES (@From);

        SET @From = @From + 1;
    END;
    RETURN;
END;

Статична таблична змінна

Якщо всі параметри виклику функції є константами (або константами виконання), план виконання один раз заповнює результат змінної таблиці. Залишок плану може отримати доступ до змінної таблиці багато разів. Статичний характер змінної таблиці може бути розпізнаний з плану виконання. Наприклад:

SELECT
    IR.n,
    IR.ts 
FROM dbo.IntegerRange(1, 5) AS IR
ORDER BY
    IR.n;

Повертає результат, подібний до:

Простий результат

План виконання:

Простий план виконання

Оператор Послідовність спочатку викликає оператора «Функція табличної функції», який заповнює змінну таблиці (зверніть увагу, що цей оператор не повертає рядків). Далі послідовність викликає другий вхід, який повертає вміст змінної таблиці (використовуючи кластерне сканування індексів у цьому випадку).

Передача, що в плані використовується результат "статичної" змінної таблиці, є оператор "Таблиця оцінених функцій" під послідовністю - змінну таблиці потрібно повністю заповнити один раз, перш ніж решта плану може розпочати роботу.

Кілька доступів

Щоб показати результат змінної таблиці, до якого зверталися не один раз, ми будемо використовувати другу таблицю з рядками, пронумерованими від 1 до 5:

IF OBJECT_ID(N'dbo.T', 'U') IS NOT NULL
    DROP TABLE dbo.T;

CREATE TABLE dbo.T (i integer NOT NULL);

INSERT dbo.T (i) 
VALUES (1), (2), (3), (4), (5);

І новий запит, який приєднує цю таблицю до нашої функції (це однаково можна записати як APPLY):

SELECT T.i,
       IR.n,
       IR.ts
FROM dbo.T AS T
JOIN dbo.IntegerRange(1, 5) AS IR
    ON IR.n = T.i;

Результат:

Приєднайтесь до результату

План виконання:

Приєднайтесь до плану

Як і раніше, послідовність спочатку заповнює табличну змінну результату msTVF. Далі, вкладені петлі використовуються для приєднання кожного рядка від таблиці Tдо рядка з результату msTVF. Оскільки визначення функції включало корисний індекс для змінної таблиці, пошук індексу може бути використаний.

Ключовим моментом є те, що коли параметри для MSTVF є константами (включаючи змінні та параметри) або розглядаються як константи часу виконання для оператора виконавчого механізму, план містить два окремих оператора для результату змінної таблиці MSTVF: один для заповнення стіл; інший, щоб отримати доступ до результатів, можливо, отримати доступ до таблиці кілька разів і, можливо, використовувати індекси, оголошені у визначенні функції.

Співвіднесені параметри та непостійні параметри

Щоб виділити відмінності, коли використовуються корельовані параметри (зовнішні посилання) або нестабільні параметри функції, ми змінимо вміст таблиці, Tщоб функція мала набагато більше роботи:

TRUNCATE TABLE dbo.T;

INSERT dbo.T (i) 
VALUES (50001), (50002), (50003), (50004), (50005);

Наступний модифікований запит тепер використовує зовнішнє посилання на таблицю Tв одному з параметрів функції:

SELECT T.i,
       IR.n,
       IR.ts
FROM dbo.T AS T
CROSS APPLY dbo.IntegerRange(1, T.i) AS IR
WHERE IR.n = T.i;

Цей запит займає близько 8 секунд, щоб повернути такі результати, як:

Корельований результат

Зауважте різницю в часі між рядками в стовпці ts. WHEREПоложення обмежує кінцевий результат для розсудливо обсягу виробництва, але неефективна функції все ще потрібен якийсь час , щоб заповнити змінні таблиці з 50000-непарними рядками ( в залежності від корельованого значення iз таблиці T).

План виконання:

Співвіднесений план виконання

Зауважте відсутність оператора Sequence. Тепер існує єдиний оператор Table Valued Function, який заповнює змінну таблиці та повертає її рядки на кожній ітерації вкладених циклів.

Щоб було зрозуміло: лише 5 рядків у таблиці T оператор «Функція оціненої таблиці» працює 5 разів. Він генерує 50 001 рядків на першій ітерації, 50,002 на другій ... і так далі. Змінна таблиця "викидається" (усічена) між ітераціями, тому кожен з п'яти викликів є повною сукупністю. Ось чому це так повільно, і кожен рядок займає приблизно однаковий час, щоб відобразитися в результаті.

Бічні нотатки:

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

Розумне здійснення вищевказаного коду буде встановити обидва параметр msTVF до i, і видалити надлишок WHEREположення. Змінна таблиці все одно буде обрізана та повторно заселена на кожній ітерації, але лише з одного рядка кожен раз.

Ми також могли отримати мінімальні та максимальні iзначення Tта зберегти їх у змінних на попередньому кроці. Виклик функції зі змінними замість корельованих параметрів дозволить використовувати "статичну" таблицю змінної таблиці, як було зазначено раніше.

Кешування на незмінні корельовані параметри

Повертаючись до вирішення вихідного питання ще раз, коли статичну схему послідовності неможливо використовувати, SQL Server може уникнути обрізання та перенаселення змінної таблиці MSTVF, якщо жоден з корельованих параметрів не змінився з моменту попередньої ітерації вкладеного циклу приєднання.

Щоб продемонструвати це, ми замінимо вміст Tп'яти однакових i значень:

TRUNCATE TABLE dbo.T;

INSERT dbo.T (i) 
VALUES (50005), (50005), (50005), (50005), (50005);

Запит з корельованим параметром знову:

SELECT T.i,
       IR.n,
       IR.ts
FROM dbo.T AS T
CROSS APPLY dbo.IntegerRange(1, T.i) AS IR
WHERE IR.n = T.i;

Цього разу результати з’являються приблизно через 1,5 секунди :

Ідентичні результати рядків

Зверніть увагу на однакові часові позначки в кожному рядку. Кешований результат у змінній таблиці повторно використовується для наступних ітерацій, коли співвідносне значення iне змінюється. Повторне використання результату набагато швидше, ніж кожен раз вставляючи 50,005 рядків.

План виконання дуже схожий на попередній:

Плануйте однакові рядки

Ключова відмінність полягає у властивостях Actual Rebinds and Actual Rewinds оператора Таблицької функції:

Властивості оператора

Коли корельовані параметри не змінюються, SQL Server може відтворювати (перемотувати) поточні результати в змінну таблиці. Коли кореляція змінюється, SQL Server повинен усікати та повторно заселяти змінну таблиці (відновлювати). Один рендінг відбувається при першій ітерації; чотири наступні ітерації - це всі перемотування назад, оскільки значення T.iне змінюється.

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