Так.
Якщо не вказати WITH SCHEMABINDING
засоби, SQL Server пропускає детальні перевірки, які він зазвичай робить на тілі функції. Він просто позначає функцію як доступ до даних (як зазначено у посиланні, наведеному у питанні).
Це оптимізація продуктивності. Якщо б цього не було зроблено, SQL Server повинен був би здійснити детальну перевірку кожного виклику функції (оскільки незв'язана функція може змінитися в будь-який час).
Існує п'ять важливих властивостей функції:
- Детермінізм
- Точність
- Доступ до даних
- Доступ до системних даних
- Перевірка системи
Наприклад, візьміть таку незв'язану скалярну функцію:
CREATE FUNCTION dbo.F
(
@i integer
)
RETURNS datetime
AS
BEGIN
RETURN '19000101';
END;
Ми можемо розглянути п’ять властивостей за допомогою функції метаданих:
SELECT
IsDeterministic = OBJECTPROPERTYEX(Func.ID, 'IsDeterministic'),
IsPrecise = OBJECTPROPERTYEX(Func.ID, 'IsPrecise'),
IsSystemVerified = OBJECTPROPERTYEX(Func.ID, 'IsSystemVerified'),
UserDataAccess = OBJECTPROPERTYEX(Func.ID, 'UserDataAccess'),
SystemDataAccess = OBJECTPROPERTYEX(Func.ID, 'SystemDataAccess')
FROM (VALUES(OBJECT_ID(N'dbo.F', N'FN'))) AS Func (ID);
Дві властивості доступу до даних встановлені істинними, а інші три встановлені помилковими .
Це має наслідки, ніж ті, які можна очікувати (наприклад, використання в індексованих поданнях або індексованих обчислених стовпцях).
Вплив на оптимізатор запитів
Детермінізм властивість , зокрема , впливає на оптимізатор запитів. У ньому є детальні правила стосовно типів переписувань та маніпуляцій, які дозволяється виконувати, і вони дуже обмежені для недетермінованих елементів. Побічні ефекти можуть бути досить тонкими.
Наприклад, розглянемо наступні дві таблиці:
CREATE TABLE dbo.T1
(
SomeInteger integer PRIMARY KEY
);
GO
CREATE TABLE dbo.T2
(
SomeDate datetime PRIMARY KEY
);
... і запит, який використовує функцію (як визначено раніше):
SELECT *
FROM dbo.T1 AS T1
JOIN dbo.T2 AS T2
ON T2.SomeDate = dbo.F(T1.SomeInteger);
План запитів, як очікується, містить запит на таблицю T2:
Однак якщо той самий логічний запит записується за допомогою похідної таблиці або вираження загальної таблиці:
WITH CTE AS
(
SELECT *, dt = dbo.F(T1.SomeInteger)
FROM dbo.T1 AS T1
)
SELECT *
FROM CTE
JOIN dbo.T2 AS T2
ON T2.SomeDate = CTE.dt;
-- Derived table
SELECT
*
FROM
(
SELECT *, dt = dbo.F(T1.SomeInteger)
FROM dbo.T1 AS T1
) AS T1
JOIN dbo.T2 AS T2
ON T2.SomeDate = T1.dt;
План виконання тепер містить сканування, при цьому предикат включає функцію, застрягнуту у Фільтр:
Це також відбувається, якщо виведене вираження таблиці або загальний табличний вираз замінено функцією перегляду або рядка. FORCESEEK
Натяк (і інші подібні спроби) не вдасться:
Основоположне питання полягає в тому, що оптимізатор запитів не може вільно змінювати недетерміновані елементи запиту .
Щоб здійснити пошук, предикат фільтра потрібно було б перемістити вниз по плану до доступу до даних T2. Цей рух запобігається, коли функція не є детермінованою.
Виправити
Виправлення цього прикладу включає два етапи:
- Додайте
WITH SCHEMABINDING
- Зробіть функцію детермінованою
Перший крок - тривіальний. Другий включає вилучення недетермінованого неявного виступу з рядка до datetime
; замінивши її детермінованою CONVERT
. Жоден із них недостатній сам по собі .
ALTER FUNCTION dbo.F
(
@i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
-- Convert with a deterministic style
RETURN CONVERT(datetime, '19000101', 112);
END;
Властивості функції тепер:
Коли оптимізатор звільнився, усі приклади тепер створюють бажаний план пошуку .
Зверніть увагу , що використання CAST
для datetime
в функції не буде працювати, тому що це не представляється можливим визначити стиль перетворення в цьому синтаксисі:
ALTER FUNCTION dbo.F
(
@i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
-- Convert with a deterministic style
RETURN CAST('19000101' AS datetime);
END;
Це визначення функції виробляє план сканування, і властивості показують, що він залишається недетермінованим: