L'indice sulla colonna calcolata persistenza ha bisogno di una ricerca chiave per ottenere colonne nell'espressione calcolata

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

Domanda

Ho una colonna calcolata persistita su una tabella che è semplicemente composta da colonne concatenate, ad esempio

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

In questo Comp non è unico e d è valida dalla data di ogni combinazione di A, B, C, quindi uso la seguente query per ottenere la data di fine per ciascuno A, B, C (Fondamentalmente la data di inizio successiva per lo stesso valore di 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;

Ho quindi aggiunto un indice alla colonna calcolata per aiutare in questa query (e anche altri):

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

Il piano di query comunque mi ha sorpreso. Avrei pensato che da quando avevo una clausola dove lo afferma D IS NOT NULL E sto ordinando Comp, e non fare riferimento a nessuna colonna al di fuori dell'indice che l'indice sulla colonna calcolata potrebbe essere utilizzato per scansionare T1 e T2, ma ho visto una scansione indice cluster.

enter image description here

Quindi ho costretto l'uso di questo indice per vedere se ha prodotto un piano migliore:

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;

Che ha dato questo piano

enter image description here

Ciò dimostra che viene utilizzata una ricerca chiave, i cui dettagli sono:

enter image description here

Ora, secondo la documentazione SQL-Server:

È possibile creare un indice su una colonna calcolata che è definita con un'espressione deterministica, ma imprecisa, se la colonna è contrassegnata nella tabella Crea o altera la tabella. Ciò significa che il motore del database memorizza i valori calcolati nella tabella e li aggiorna quando vengono aggiornate altre colonne da cui dipende la colonna calcolata. Il motore del database utilizza questi valori persistiti quando crea un indice sulla colonna e quando l'indice viene referenziato in una query. Questa opzione consente di creare un indice su una colonna calcolata quando il motore del database non può dimostrare con precisione se una funzione che restituisce espressioni di colonna calcolata, in particolare una funzione CLR creata nel framework .NET, è sia deterministica che precisa.

Quindi, come dicono i documenti "Il motore del database memorizza i valori calcolati nella tabella", E anche il valore viene archiviato nel mio indice, perché è richiesta una ricerca chiave per ottenere A, B e C quando non sono affatto referenziati nella query? Presumo che siano usati per calcolare COMP, ma perché? Inoltre, perché la query può utilizzare l'indice su t2, ma non su t1?

Query e ddl sul violino SQL

NB Ho taggato SQL Server 2008 perché questa è la versione su cui si trova il mio problema principale, ma ho anche lo stesso comportamento nel 2012.

Nessuna soluzione corretta

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a dba.stackexchange
scroll top