Oui.
Si vous ne spécifiez pas WITH SCHEMABINDING
, SQL Server ignore les vérifications détaillées qu'il effectue normalement sur le corps de la fonction. Cela indique simplement que la fonction accède aux données (comme indiqué dans le lien indiqué dans la question).
Ceci est une optimisation des performances. Si ce n’est pas le cas, SQL Server devra effectuer les contrôles détaillés à chaque appel de fonction (la fonction non liée pouvant être modifiée à tout moment).
Il y a cinq propriétés de fonction importantes:
- Déterminisme
- Précision
- Accès aux données
- Accès aux données du système
- Vérification du système
Par exemple, prenons la fonction scalaire non liée suivante:
CREATE FUNCTION dbo.F
(
@i integer
)
RETURNS datetime
AS
BEGIN
RETURN '19000101';
END;
Nous pouvons examiner les cinq propriétés à l'aide d'une fonction de métadonnées:
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);
Les deux propriétés d'accès aux données ont été définies sur true et les trois autres sur false .
Cela a des implications qui vont bien au-delà de ce à quoi on pourrait s'attendre (utilisation dans les vues indexées ou les colonnes calculées indexées, par exemple).
Effets sur l'optimiseur de requête
La propriété Déterminisme affecte en particulier l'optimiseur de requêtes. Il a des règles détaillées concernant les types de réécriture et de manipulations qu'il est autorisé à effectuer et celles-ci sont très limitées pour les éléments non déterministes. Les effets secondaires peuvent être assez subtils.
Par exemple, considérons les deux tables suivantes:
CREATE TABLE dbo.T1
(
SomeInteger integer PRIMARY KEY
);
GO
CREATE TABLE dbo.T2
(
SomeDate datetime PRIMARY KEY
);
... et une requête utilisant la fonction (telle que définie précédemment):
SELECT *
FROM dbo.T1 AS T1
JOIN dbo.T2 AS T2
ON T2.SomeDate = dbo.F(T1.SomeInteger);
Le plan de requête est comme prévu, avec une recherche dans la table T2:
Toutefois, si la même requête logique est écrite à l'aide d'une table dérivée ou d'une expression de table commune:
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;
Le plan d'exécution comporte désormais une analyse, avec le prédicat impliquant la fonction bloquée dans un filtre:
Cela se produit également si la table dérivée ou l'expression de table commune est remplacée par une vue ou une fonction en ligne. Un FORCESEEK
indice (et d'autres tentatives similaires) ne réussira pas:
Le problème fondamental est que l'optimiseur de requêtes ne peut pas réorganiser aussi librement les éléments de requête non déterministes .
Pour produire une recherche, le prédicat Filter doit être déplacé du plan vers l'accès aux données T2. Ce mouvement est empêché lorsque la fonction est non déterministe.
Réparer
Le correctif de cet exemple implique deux étapes:
- Ajouter
WITH SCHEMABINDING
- Rendre la fonction déterministe
La première étape est triviale. La seconde implique la suppression de la conversion implicite non déterministe de string to datetime
; le remplacer par un déterministe CONVERT
. Ni est suffisant en soi .
ALTER FUNCTION dbo.F
(
@i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
-- Convert with a deterministic style
RETURN CONVERT(datetime, '19000101', 112);
END;
Les propriétés de la fonction sont maintenant:
Avec l'optimiseur libéré, tous les exemples produisent maintenant le plan de recherche souhaité .
Notez que l'utilisation de CAST
to datetime
dans la fonction ne fonctionnerait pas, car il n'est pas possible de spécifier un style de conversion dans cette syntaxe:
ALTER FUNCTION dbo.F
(
@i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
-- Convert with a deterministic style
RETURN CAST('19000101' AS datetime);
END;
Cette définition de fonction produit le plan d'analyse et les propriétés indiquent qu'il reste non déterministe: