Creazione di un indice non cluster su SQL Server colonna calcolata non persistente


10

Faccio fatica a trovare tutta la documentazione su come SQL Server memorizza effettivamente una colonna calcolata non persistente.

Prendi il seguente esempio:

--SCHEMA
CREATE TABLE dbo.Invoice
(
    InvoiceID INT IDENTITY(1, 1) PRIMARY KEY,
    CustomerID INT FOREIGN KEY REFERENCES dbo.Customer(CustomerID),
    InvoiceStatus NVARCHAR(50) NOT NULL,
    InvoiceStatusID AS CASE InvoiceStatus 
                         WHEN 'Sent' THEN 1 
                         WHEN 'Complete' THEN 2
                         WHEN 'Received' THEN 3
                       END
)
GO

--INDEX
CREATE NONCLUSTERED INDEX IX_Invoice ON Invoice
(
    CustomerID ASC
)
INCLUDE
(
    InvoiceStatusID
)
GO

Capisco che sia memorizzato a livello foglia, ma se il valore non è persistente come viene archiviato qualcosa? In che modo l'indice aiuta SQL Server a trovare queste righe in questa situazione?

Qualsiasi aiuto molto apprezzato,

Grazie molto,

MODIFICARE:

Grazie a Brent e Aaron per aver risposto, ecco il PasteThePlan che mostra chiaramente ciò che hanno spiegato.


5
Non è persistente nelle pagine di dati della tabella, ma è persistente nelle pagine dell'indice .
Aaron Bertrand

Le colonne calcolate non persistenti non vengono archiviate fisicamente nella tabella. Sono colonne virtuali. I loro valori vengono ricalcolati ogni volta che fanno riferimento a una query. vedi questo rif .
Kin Shah,

Risposte:


11

Quando SQL Server crea l'indice sul campo calcolato, il campo calcolato viene scritto sul disco in quel momento, ma solo sulle pagine 8K di tale indice. SQL Server può calcolare InvoiceStatusID mentre legge l'indice cluster: non è necessario scrivere quei dati nell'indice cluster.

Mentre elimini / aggiorni / inserisci righe in dbo.Invoice, i dati negli indici vengono mantenuti aggiornati. (Quando InvoiceStatus cambia, SQL Server sa anche aggiornare IX_Invoice.)

Il modo migliore per vederlo da solo è effettivamente farlo: creare questi oggetti ed eseguire gli aggiornamenti che toccano il campo InvoiceStatusID. Pubblica il piano di esecuzione (PasteThePlan.com è utile per questo) se vuoi aiuto per vedere dove stanno avvenendo gli aggiornamenti dell'indice.


1
@ Uberzen1 No, come ha spiegato, è scritto nelle pagine dell'indice al momento dell'inserimento / aggiornamento. Non è necessario ricalcolare nulla se l'indice viene utilizzato per accedere alla colonna.
Aaron Bertrand

Ah! Sono con te adesso, scusa!
Uberzen1

6
@blobbles bene, senza offesa, ma non penso che sia su Brent. Potrebbero incollare lo stesso XML su dropbox, forum MSDN, qui, praticamente ovunque online ... ogni servizio online ora deve essere responsabile di segreti che potrebbero essere divulgati da persone che caricano file lì?
Aaron Bertrand

2
@blobbles sì, proprio non puoi impedire alle persone di condividere troppo. Ehi, a proposito, seguimi su Instagram - sono BrentO - e condivido le foto della mia colazione lì. ;-)
Brent Ozar

4
@blobbles nel link Privacy, afferma: I dati che copi / incolla qui sono pubblici . Chiunque può leggerlo. Non c'è sicurezza.
ypercubeᵀᴹ

8

Il valore per una colonna calcolata indicizzata e non persistente non è persistente nelle pagine di dati della tabella , ma è persistente nelle pagine dell'indice . Rimane non persistente nella tabella, indipendentemente dal fatto che sia persistente in 0, 1 o in più indici.

Giusto per illustrare la descrizione di Brent, prendendo l'esempio che hai dato, inseriamo una riga:

INSERT dbo.Invoice(CustomerID, InvoiceStatus) VALUES(1,N'Sent');

Ora vediamo le pagine dell'indice:

DBCC TRACEON(3604, -1);
DBCC IND(N'dbname', N'dbo.Invoice', 2);

(Ovviamente cambia dbnamee l'ID indice potrebbe non essere 2 nel tuo caso.)

Output (il tuo sarà sicuramente diverso):

inserisci qui la descrizione dell'immagine

E infine, ispezioniamo la pagina per PageType2:

DBCC PAGE(7, 1, 584, 3);

(Probabilmente dovrai cambiare 7 in modo che corrisponda all'ID del tuo database e, se hai più file di dati, potresti dover cambiare il secondo argomento in modo che corrisponda PageFIDal primo risultato.)

Produzione:

inserisci qui la descrizione dell'immagine

È sulla pagina dell'indice.


Molto bello, grazie Aaron. Il motivo per cui ho posto la domanda inizialmente è che sto avendo dei veri problemi a implementare un indice simile nel mondo reale e ho voluto capire esattamente cosa sta succedendo sotto il cofano in modo da poter capire il problema. Questo aiuta molto, grazie!
Uberzen1

1
@ Uberzen1 Puoi definire "guai reali"? Pubblica una domanda su questo problema?
Aaron Bertrand

Potrei farlo, stavo per approfondire prima me stesso, ma volevo solo capire cosa sta facendo esattamente l'istruzione create index. Il TLDR è; Ho una grande tabella simile alla tabella delle fatture sopra, ha circa 400m di record e, sfortunatamente, la colonna OrderStatus è stata schiaffeggiata al centro di essa, rendendo l'indicizzazione ecc. Un po 'dolorosa. Abbiamo aggiunto una colonna calcolata per ora che alla fine persisteremo e sposteremo il campo varchar nella sua tabella. 1/2
Uberzen1

5
@ Uberzen1 Sì, poiché la colonna calcolata è effettivamente materializzata sul disco quando si scrive nell'indice, è necessario registrare tutta quell'attività. Una soluzione alternativa potrebbe essere quella di smettere di fare affidamento sulla colonna calcolata - mettere quell'espressione in una vista o le query ad hoc, e se questa non è un'opzione è possibile creare una nuova colonna nullable, aggiornarla in blocchi (per evitare l'uccisione del registro) , quindi rilascia la colonna calcolata, rinomina la nuova colonna e modifica il DML per scriverlo manualmente. Ma proprio dal momento che sono informazioni ridondanti che puoi derivare da dati esistenti, opterei per la prima opzione.
Aaron Bertrand

2
Grazie mille Aaron. Sono contento che tu abbia menzionato il fatto di averlo visto di fronte anche perché quella era la mia soluzione, forse è tempo di rivisitare quell'idea!
Uberzen1,

7

L'attributo PERSISTEDper una colonna calcolata si riferisce alla persistenza dei valori nella tabella (indice cluster o heap) e non alla persistenza dei valori nell'indice.

Il CREATE INDEXha i requisiti per le limitazioni relative colonne e indici calcolate:

Le colonne calcolate che sono deterministiche e precise o imprecise possono essere incluse colonne. Le colonne calcolate derivate da image, ntext, text, varchar (max), nvarchar (max), varbinary (max) e tipi di dati xml possono essere incluse in colonne non chiave purché i tipi di dati della colonna calcolata siano consentiti come inclusi colonna. Per ulteriori informazioni, consultare Indici su colonne calcolate.

Non ci sono limiti sul fatto che la colonna calcolata sia persistente o meno.

e inoltre (non sulle colonne incluse ma sulle colonne calcolate nella parte principale di un indice):

Gli indici possono essere creati su colonne calcolate. Inoltre, le colonne calcolate possono avere la proprietà PERSISTED. Ciò significa che 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.

Per indicizzare una colonna calcolata, la colonna calcolata deve (essere) deterministica e precisa. Tuttavia, l'utilizzo della PERSISTEDproprietà espande il tipo di colonne calcolate indicizzabili per includere:

...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.