Ho notato che pochissime persone capiscono come funzionano gli indici in SQL Server, in particolare le colonne incluse. Tuttavia, gli indici sono un ottimo modo per ottimizzare le query. All'inizio non avevo nemmeno l'idea delle colonne incluse, ma i miei esperimenti hanno dimostrato che sono molto utili.
Supponiamo di avere la seguente tabella e query:
CREATE TABLE Person ( PersonID int, FirstName varchar(100), LastName varchar(100), Age int, … … ) SELECT FirstName, LastName, Age FROM Person WHERE FirstName = 'John' and LastName = 'Smith'
È chiaro che PersonID è una chiave primaria. Supponiamo di avere un indice in base al nome e al cognome, chiamiamolo IX_Person_FirstNameLastName. Il piano di esecuzione per tale query sarà il seguente:
- Individuare tutte le righe con il nome e il cognome specificati con l'aiuto dell'albero dell'indice IX_Person_FirstNameLastName
- Rilevare la posizione effettiva della riga sul disco sulle foglie dell'indice, andare alla posizione effettiva e leggere l'età.
Consideriamo ora che questa query viene eseguita abbastanza frequentemente. Dobbiamo eseguire 2 passaggi ogni volta. Può essere ottimizzato? In caso di MS SQL Server, non è un problema:puoi includere i valori direttamente nell'indice con l'aiuto dell'opzione INCLUDE.
CREATE INDEX IX_PERSON ON Person ( FirstName, LastName ) INCLUDE(Age)
Ora, questo campo non viene utilizzato durante l'indicizzazione ma è incluso nell'indice. Quali problemi possiamo incontrare in questo senso? Quando indicizziamo una tabella in base a un determinato campo, il server di database deve creare un albero di indicizzazione in base a questo campo. Ciò significa che è necessario modificare l'albero dell'indice quando si cambia il valore. Quando i valori vengono modificati in modo intensivo, diventa un compito problematico e difficile per il server. Quando l'aggiornamento diventa troppo massiccio, a volte è più facile eliminare l'indice. Indice ottimizza notevolmente la ricerca ma influisce negativamente sulle operazioni di inserimento, eliminazione e aggiornamento.
Se un campo è semplicemente incluso in un indice, non viene utilizzato durante la creazione di un albero dell'indice e non lo influisce, ma il il valore può essere facilmente trovato sulla foglia di questo albero. Quando viene eseguita una ricerca per cognome e nome, il server ricerca tutti i nomi e cognomi dall'albero e quando raggiunge la foglia (trova il valore di indice richiesto), oltre al puntatore alla posizione fisica dei valori di riga, contiene anche i valori di campo inclusi nell'indice. Significa che non è necessario fare il secondo passaggio per passare alla posizione fisica della linea e leggerla da lì.
Dal momento che non è necessario modificare l'albero quando si modificano i dati sull'età, tutta questa roba non influisce molto sulle operazioni di modifica dei dati. Non abbiamo bisogno di cambiare l'indice, dobbiamo solo cambiare i valori sulla foglia dell'albero. Ecco perché anche un massiccio cambiamento del campo dell'età non avrà un grande impatto sulle prestazioni. Influirà sicuramente, ma non così tanto.
Per quanto ne so, i valori dell'indice cluster sono inclusi automaticamente nel livello foglia, ma questo deve essere verificato con la specifica.
Quindi, quando l'uso dei campi inclusi è vantaggioso? Quando vengono utilizzati frequentemente nei risultati delle query ma vengono modificati di tanto in tanto. Un esempio è una tabella delle transazioni bancarie. Tale tabella può essere composta dai seguenti campi:numero di conto, tipo di transazione, data, somma. Non ha senso indicizzare la somma, ma possiamo includerla nell'indice e velocizzerà notevolmente la query.
Per recuperare l'effetto reale dall'indicizzazione, le query non dovrebbero selezionare tutti i campi, ovvero dovremmo dimenticare SELECT * FROM table. Ricalcola sempre solo i campi di cui hai veramente bisogno. E se i loro valori vengono a trovarsi nell'indice, la velocità di esecuzione potrebbe essere piuttosto alta.
Strumento utile:
dbForge Index Manager – pratico componente aggiuntivo SSMS per analizzare lo stato degli indici SQL e risolvere i problemi con la frammentazione degli indici.