Index sur la colonne calculée persistante nécessite une recherche de clé pour obtenir des colonnes dans l'expression calculée

dba.stackexchange https://dba.stackexchange.com/questions/52129

Question

J'ai une colonne calculée persistante sur une table qui est simplement constituée de colonnes concaténées, par exemple

CREATE TABLE dbo.T 
(   
    ID INT IDENTITY(1, 1) NOT NULL CONSTRAINT PK_T_ID PRIMARY KEY,
    A VARCHAR(20) NOT NULL,
    B VARCHAR(20) NOT NULL,
    C VARCHAR(20) NOT NULL,
    D DATE NULL,
    E VARCHAR(20) NULL,
    Comp AS A + '-' + B + '-' + C PERSISTED NOT NULL 
);

Dans ce Comp n'est pas unique, et d est le valide à partir de la date de chaque combinaison de A, B, C, Par conséquent, j'utilise la requête suivante pour obtenir la date de fin pour chaque A, B, C (Fondamentalement, la date de début suivante pour la même valeur de comp):

SELECT  t1.ID,
        t1.Comp,
        t1.D,
        D2 = (  SELECT  TOP 1 t2.D
                FROM    dbo.T t2
                WHERE   t2.Comp = t1.Comp
                AND     t2.D > t1.D
                ORDER BY t2.D
            )
FROM    dbo.T t1
WHERE   t1.D IS NOT NULL -- DON'T CARE ABOUT INACTIVE RECORDS
ORDER BY t1.Comp;

J'ai ensuite ajouté un index à la colonne calculée pour aider dans cette requête (et aussi d'autres):

CREATE NONCLUSTERED INDEX IX_T_Comp_D ON dbo.T (Comp, D) WHERE D IS NOT NULL;

Le plan de requête m'a cependant surpris. J'aurais pensé que depuis que j'ai une clause où indiquer que D IS NOT NULL Et je trie par Comp, et ne faisant référence à aucune colonne en dehors de l'index que l'index de la colonne calculée pourrait être utilisé pour scanner T1 et T2, mais j'ai vu une analyse d'index cluster.

enter image description here

J'ai donc forcé l'utilisation de cet indice pour voir s'il a donné un meilleur plan:

SELECT  t1.ID,
        t1.Comp,
        t1.D,
        D2 = (  SELECT  TOP 1 t2.D
                FROM    dbo.T t2
                WHERE   t2.Comp = t1.Comp
                AND     t2.D > t1.D
                ORDER BY t2.D
            )
FROM    dbo.T t1 WITH (INDEX (IX_T_Comp_D))
WHERE   t1.D IS NOT NULL
ORDER BY t1.Comp;

Qui a donné ce plan

enter image description here

Cela montre qu'une recherche clé est utilisée, dont les détails sont:

enter image description here

Maintenant, selon la documentation SQL-Server:

Vous pouvez créer un index sur une colonne calculée qui est définie avec une expression déterministe, mais imprécise, si la colonne est marquée persistante dans l'instruction Create Table ou Alter Table. Cela signifie que le moteur de base de données stocke les valeurs calculées dans le tableau et les met à jour lorsque les autres colonnes sur lesquelles la colonne calculée dépend est mise à jour. Le moteur de la base de données utilise ces valeurs persistantes lorsqu'elle crée un index sur la colonne et lorsque l'index est référencé dans une requête. Cette option vous permet de créer un index sur une colonne calculée lorsque le moteur de base de données ne peut pas prouver avec précision si une fonction qui renvoie les expressions de colonne calculées, en particulier une fonction CLR qui est créée dans le framework .NET, est à la fois déterministe et précise.

Donc si, comme le disent les documents "Le moteur de base de données stocke les valeurs calculées dans le tableau", et la valeur est également stockée dans mon index, pourquoi une recherche clé est-elle requise pour obtenir A, B et C alors qu'ils ne sont pas du tout référencés dans la requête? Je suppose qu'ils sont utilisés pour calculer Comp, mais pourquoi? Aussi, pourquoi la requête peut-elle utiliser l'index sur t2, mais pas sur t1?

Requêtes et DDL sur le violon SQL

NB J'ai tagué SQL Server 2008 parce que c'est la version sur laquelle est mon problème principal, mais j'obtiens également le même comportement en 2012.

Pas de solution correcte

Licencié sous: CC-BY-SA avec attribution
Non affilié à dba.stackexchange
scroll top