Ho una colonna calcolata persistente su una tabella che è semplicemente composta da colonne concatenate, ad es
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 è univoco e D è la data di inizio valida di ciascuna combinazione di A, B, C, quindi utilizzo la seguente query per ottenere la data di fine per ciascuna A, B, C(sostanzialmente 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 in altri):
CREATE NONCLUSTERED INDEX IX_T_Comp_D ON dbo.T (Comp, D) WHERE D IS NOT NULL;
Il piano di query tuttavia mi ha sorpreso. Avrei pensato che da quando ho una clausola where che lo affermaD IS NOT NULL e sto ordinando per Comp, e non facendo riferimento a nessuna colonna esterna all'indice, l'indice sulla colonna calcolata potrebbe essere usato per scansionare t1 e t2, ma ho visto un indice cluster scansione.

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

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

Ora, secondo la documentazione di SQL Server:
È possibile creare un indice su una colonna calcolata definita con un'espressione deterministica, ma imprecisa, se la colonna è contrassegnata come PERSISTED nell'istruzione CREATE TABLE o ALTER TABLE. Ciò significa che il Motore di database memorizza i valori calcolati nella tabella e li aggiorna quando vengono aggiornate eventuali altre colonne da cui dipende la colonna calcolata. Motore di database utilizza questi valori persistenti quando crea un indice sulla colonna e quando si fa riferimento all'indice in una query. Questa opzione consente di creare un indice su una colonna calcolata quando Motore di database non è in grado di dimostrare con precisione se una funzione che restituisce espressioni di colonne calcolate, in particolare una funzione CLR creata in .NET Framework, sia deterministica e precisa.
Quindi se, come dicono i documenti "Motore di database memorizza i valori calcolati nella tabella" e il valore viene anche memorizzato nel mio indice, perché è richiesta una Ricerca chiave per ottenere A, B e C quando non sono referenziati in la domanda a tutti? Presumo che vengano utilizzati per calcolare Comp, ma perché? Inoltre, perché la query può utilizzare l'indice su t2, ma non su t1?
NB Ho taggato SQL Server 2008 perché questa è la versione in cui si trova il mio problema principale, ma ho anche lo stesso comportamento nel 2012.






