La prima cosa che chiedo è se esiste una buona ragione per una tabella di tale dimensione non ha un indice cluster? Una chiave in cluster non deve nemmeno essere univoca (in caso contrario, SQL Server aggiungerà un "unificatore", sebbene di solito sia preferibile utilizzare una colonna IDENTITY).
per rispondere alle vostre due domande:
1) La raccomandazione indice è correlato alla query è in esecuzione. Come regola generale, le colonne suggerite corrisponderanno le colonne l'ottimizzatore di query sta usando per sondare nella tabella, quindi se avete una query come:
SELECT field1, field2, field3
FROM table1
WHERE field4 = 1 AND field5 = 'bob'
L'indice suggerito è probabile che sia sul field4
e field5
colonne e in ordine di selettività (ovvero la colonna con la maggior parte delle variazioni nei valori per primi). Può includere altre colonne (ad esempio field1, field2, field3
) perché in tal caso lo strumento di ottimizzazione delle query dovrà solo visitare l'indice per ottenere tali dati e non visitare la pagina dei dati.
Nota anche che a volte l'indice suggerito non è sempre quello che potresti scegliere tu stesso. Se si aggiungono più tabelle, Query Optimiser sceglierà il piano di esecuzione che ritiene più adatto ai dati, in base agli indici e alle statistiche disponibili. Potrebbe scorrere su un tavolo e sondare in un altro, quando il miglior piano possibile potrebbe farlo al contrario. Devi controllare il piano di esecuzione della query per vedere cosa sta succedendo.
Se si conosce che la query è sufficientemente selettiva da eseguire il drill-down su un piccolo intervallo di record (ad esempio una clausola where come WHERE table1.field1 = 1 AND table1.field2 = 'abc' AND table1.field3 = '2015-07-01' ...
), è possibile aggiungere un indice che copra tutte le colonne di riferimento. Ciò potrebbe influire sull'ottimizzatore della query per analizzare questo indice per ottenere un numero limitato di righe da unire a un'altra tabella, piuttosto che eseguire scansioni.
Come regola generale, un buon punto di partenza quando si esaminano i piani di esecuzione sta tentando di eliminare le scansioni, in cui il server leggerà una vasta gamma di righe e fornirà indici che restringono la quantità di dati che ha essere processato.
2) Penso che gli altri hanno probabilmente spiegato questo abbastanza bene ormai - le colonne incluse sono lì in modo che quando l'indice viene letto, il server non deve quindi leggere la pagina dei dati per ottenere quei valori; sono anche memorizzati nell'indice.
La risposta iniziale che molte persone possono avere quando leggono su tali "indici di copertura" è "perché non aggiungo un intero gruppo di indici che fanno questo", o "perché non aggiungo un indice che copre tutte le colonne ".
In alcune situazioni (in genere piccole tabelle con colonne strette, come le tabelle di unione molti-a-molti), ciò è utile. Tuttavia, con ogni indice aggiunto vengono alcuni costi:
In primo luogo, ogni aggiornamento o inserimento di un valore nella tabella, l'indice deve essere aggiornato. Ciò significa che dovrai affrontare il blocco, bloccare i problemi di escalation (probabilmente deadlocking), le divisioni di pagina e la frammentazione associata. Esistono vari modi per attenuare questi problemi, ad esempio l'utilizzo di un fattore di riempimento appropriato per consentire l'inserimento di più valori in una pagina dell'indice senza doverlo dividere.
In secondo luogo, gli indici occupano spazio. Per lo meno, un indice contiene i valori chiave utilizzati e il RID (in un heap) o la chiave di clustering (in una tabella con un indice cluster). Gli indici di copertura contengono anche una copia delle colonne incluse.Se si tratta di colonne di grandi dimensioni (come grandi varchar), l'indice può essere piuttosto grande e non è inaudito per gli indici di tabelle da sommare per essere più grandi della tabella stessa. Si noti che esistono anche limiti sulla dimensione di un indice, sia in termini di colonne, sia in termini di dimensioni totali. Poiché la chiave di clustering viene sempre inclusa negli indici non in cluster su una tabella con un indice cluster (l'indice cluster si trova nella stessa pagina dati), ciò significa che una chiave cluster più piccola è migliore. Sebbene sia possibile utilizzare un indice composito, è probabile che abbia una larghezza di alcuni byte e, sebbene sia possibile utilizzare una chiave non univoca, SQL Server aggiungerà tale unificatore univoco, ovvero altri 4 byte. È consigliabile utilizzare una colonna di identificazione (int, o bigint se si prevede di avere più di 2 miliardi di righe nella tabella). Anche le identità aumentano sempre, quindi non si otterranno le suddivisioni di pagina nelle pagine di dati quando si inserisce un nuovo record, poiché andrà sempre alla fine della tabella.
quindi il tl; dr; è:
Gli indici suggeriti possono essere utili, ma spesso non forniscono l'indice migliore. se si conosce la struttura dei dati e il modo in cui verranno interrogati, è possibile creare indici contenenti le chiavi di sondaggio comunemente utilizzate.
Ordinare sempre le colonne nell'indice nell'ordine selettività (vale a dire la colonna con il maggior numero di valori per primo). Questo potrebbe sembrare contro-intuitivo, ma consente a SQL Server di trovare i dati desiderati più velocemente, con meno letture.
Le colonne incluse sono utili, ma solo di solito quando sono colonne di piccole dimensioni (ad esempio numeri interi). Se la query richiede sei colonne da una tabella e l'indice copre solo cinque di esse, SQL Server dovrà comunque visitare la pagina dati, quindi in questo caso è meglio senza le colonne incluse perché occupano solo spazio e hanno un costo di manutenzione.
molto utile, grazie! – Jon