SCHEMABINDING a-t-il un avantage en dehors de la protection Halloween?


52

Il est bien connu qu'une SCHEMABINDINGfonction peut éviter un spool inutile dans les plans de mise à jour:

Si vous utilisez des fichiers UDF T-SQL simples qui ne touchent aucune table (c’est-à-dire qui n’accèdent pas aux données), assurez-vous de spécifier l’ SCHEMABINDINGoption lors de la création des fichiers UDF. Les UDF sont liées au schéma et garantissent que l'optimiseur de requêtes ne génère pas d'opérateurs de spool inutiles pour les plans de requêtes impliquant ces UDF.

Y a-t-il d'autres avantages d' SCHEMABINDINGune fonction, même si elle n'accède pas aux données?

Réponses:


78

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);

Résultat

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:

Plan de recherche

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:

Plan de numérisation

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 FORCESEEKindice (et d'autres tentatives similaires) ne réussira pas:

Message d'erreur

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:

  1. Ajouter WITH SCHEMABINDING
  2. 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:

Nouvelles propriétés

Avec l'optimiseur libéré, tous les exemples produisent maintenant le plan de recherche souhaité .


Notez que l'utilisation de CASTto datetimedans 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:

Propriétés de la fonction CAST

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.