SQL Server esiste da oltre 30 anni e lavoro con SQL Server da quasi lo stesso tempo. Kalen copre le scansioni nella prima parte di SQL Server Internals:Operatori problematici.
Ho visto molti cambiamenti nel corso degli anni (e decenni!) e delle versioni di questo incredibile prodotto. In questi post condividerò con te come considero alcune delle funzionalità o aspetti di SQL Server, a volte insieme a un po' di prospettiva storica.
L'ottimizzazione delle query di SQL Server è una delle cose migliori che puoi fare per migliorare le prestazioni e l'ottimizzazione della diagnostica del server SQL. Ma la messa a punto è un argomento enorme! Sapere esattamente come ottimizzare nel miglior modo possibile richiede non solo una conoscenza approfondita dei dati e del carico di lavoro, ma anche la conoscenza di come SQL Server effettua effettivamente le scelte di esecuzione dei piani. Quindi, cosa puoi fare se non sei un esperto di interni di SQL Server? Una cosa che puoi fare è affidarti a persone esperte, oltre che a strumenti scritti da esperti. Strumenti come Quest Spotlight Cloud Tuning Pack possono darti alcuni ottimi suggerimenti per iniziare a migliorare le prestazioni delle query. Naturalmente, nessuno strumento esterno conosce i tuoi dati e tutti i dettagli di tutti i tuoi carichi di lavoro, quindi è sempre consigliabile eseguire un test approfondito di qualsiasi suggerimento tu decida di implementare.
In questi post sugli operatori problematici, presumo che tu abbia una conoscenza di base delle strutture degli indici di SQL Server. Ecco alcune informazioni che saranno utili:
- Una tabella senza un indice cluster è chiamata heap e non ha ordinamento. Non c'è la prima o l'ultima riga. Un heap è solo un mucchio di righe senza un ordine particolare.
- Il livello foglia di un indice cluster è la tabella stessa. (Non è una copia della tabella, è la tabella.) Le righe dell'indice sono ordinate logicamente in base alla colonna definita come chiave dell'indice cluster.
- Il livello foglia di un indice non cluster contiene una riga di indice per ogni riga della tabella. Le righe contengono le colonne chiave non cluster e sono ordinate logicamente nell'ordine in cui sono specificate le chiavi. Oltre alle colonne chiave, le righe dell'indice non raggruppate contengono un "segnalibro" che punta alla riga di riferimento nella tabella. Il segnalibro può essere in una delle due seguenti forme:
- Se la tabella ha un indice cluster, il segnalibro è la chiave dell'indice cluster. (Se la chiave dell'indice cluster fa parte della chiave dell'indice non cluster, non verrà duplicata.)
- Se la tabella è un heap, il segnalibro è un ID riga, o RID, che specifica la posizione fisica della riga. La posizione è in genere specificata come FileNum:PageNum:RowNum .
Gli strumenti di SQL Server offrono diversi modi per visualizzare il piano di esecuzione delle query che l'ottimizzatore ha deciso di utilizzare per una determinata query. Con l'aggiunta di Quest Spotlight Tuning Pack, puoi ottenere ancora più informazioni sui tuoi piani.
Il codice seguente crea copie di due tabelle in AdventureWorks database (sto usando AdventureWorks2016 , ma potresti usare un'altra versione).
USE AdventureWorks2016;
GO
DROP TABLE IF EXISTS SalesHeader;
GO
SELECT *
INTO SalesHeader
FROM Sales.SalesOrderHeader;
GO
DROP TABLE IF EXISTS SalesDetail;
GO
SELECT * INTO SalesDetail
FROM Sales.SalesOrderDetail;
GO
Ora esegui una query che unisce le due tabelle, dopo aver attivato "Includi piano di esecuzione effettivo"
SELECT h.SalesOrderID, OrderDate, ProductID, UnitPrice, OrderQty
FROM SalesHeader h JOIN SalesDetail d
ON h.SalesOrderID = d.SalesOrderID
WHERE SalesOrderDetailID < 100;
GO
Quest Spotlight Tuning Pack segnalerà un problema con la query, quindi puoi fare clic su "Visualizza analisi" e scegliere l'opzione "Piano di esecuzione". Dovresti vedere quanto segue:
Comprendere le scansioni delle tabelle
Per prima cosa, voglio dire che non c'è un operatore di piano che sia sempre cattivo! Perché l'ottimizzatore dovrebbe aggiungerlo al tuo piano di query se non era valido? Potrebbe indicare che c'è spazio per migliorare i tuoi dati o le strutture degli indici, ma di per sé non è male.
Nell'esempio sopra, il Tuning Pack sembra mettere in evidenza le scansioni delle tabelle, indicando che potrebbero essere problematiche. Ma non è sempre vero che le scansioni delle tabelle sono problematiche. Una situazione molto peggiore sarebbe usare un indice non cluster per cercare una query che acceda a ogni riga della tabella. Per questa particolare domanda, sono d'accordo sul fatto che la scansione potrebbe non essere una buona cosa perché siamo interessati solo a poche righe nel SalesDetail tabella (99 righe su 121.317, o meno di un decimo percento.)
Quindi, potremmo esaminare i suggerimenti nel riquadro Analisi per la creazione di indici. Il suggerimento per il SalesDetail tabella serve per creare un indice non cluster su SalesOrderID column (la colonna nella clausola JOIN) e INCLUDE ogni altra colonna nella tabella restituita dalla query. Il suggerimento per il SalesHeader table è un indice non cluster su SalesOrderDetailId colonna, che è la colonna nella clausola WHERE, e INCLUDE OrderDate column, che è l'unica altra colonna restituita da questa tabella.
E se la nostra query fosse leggermente diversa? E se avessi eseguito questa query utilizzando SELECT * invece di un elenco di colonne specifico. Se lo provi e guardi i consigli, suggerisce di utilizzare INCLUDE per ogni colonna della tabella diversa dalla colonna della chiave singola. Sebbene un tale indice possa rendere questa particolare query un po' più veloce, potrebbe finire per rallentare altre query, in particolare le query UPDATE. Questo indice fondamentalmente è solo una copia della tabella, perché il livello foglia dell'indice conterrà ogni singola colonna della tabella. Se vedi consigli come questo, che suggeriscono un indice che includa tutte le colonne della tabella, ti consiglio vivamente di fare un passo indietro e di non crearlo alla cieca.
L'ottimizzazione delle query per la diagnostica del server SQL implica non solo la gestione degli indici, ma anche la gestione delle query stesse. Per questa particolare query, potrebbe essere meglio riscrivere la query in modo da NON utilizzare SELECT * per restituire ogni riga della tabella. Potrebbe essere sufficiente restituire solo un piccolo sottoinsieme delle colonne, quindi sarebbe sufficiente un indice molto più ristretto, come nel primo esempio.
Uno di questi indici sarebbe effettivamente un buon indice da creare? L'indice più ristretto sarà complessivamente più piccolo e sarà meno influenzato dagli aggiornamenti dei dati. Un indice su tutte le colonne è come una seconda copia della tabella, ordinata in un ordine diverso rispetto alla tabella stessa. Ci sono situazioni in cui può essere utile avere una "seconda copia" della tabella in un ordine diverso, ma ci sarà molto sovraccarico per le operazioni di modifica dei dati. L'unico modo per saperlo con certezza è provare le raccomandazioni su un sistema di test con un carico di lavoro rappresentativo. Solo tu conosci i tuoi dati e le tue domande, quindi provalo e guarda!
Comprendere le scansioni degli indici
Come accennato in precedenza, le scansioni delle tabelle non sono sempre una cosa negativa. Ma per quanto riguarda le scansioni degli indici? Poiché un livello foglia indice cluster è la tabella stessa, una scansione indice cluster è la stessa di una scansione tabella! se una scansione della tabella non è valida, una scansione dell'indice cluster è altrettanto negativa. Ma non è sempre male. Ancora una volta, devi testarlo sul tuo sistema.
I consigli di SQL Server Engine mostrati da Quest Spotlight Tuning Pack non suggeriscono mai un indice cluster. può suggerire un non cluster che include ogni colonna della tabella (come menzionato in precedenza), che è solo un duplicato della tabella. Capire la colonna o le colonne migliori per il tuo indice cluster è di per sé un argomento importante, quindi non ne parlerò qui.
Cos'è una ricerca? Un'operazione di ricerca in un piano significa che SQL Server sta usando i dati ordinati nella struttura dell'indice per trovare una riga, un insieme di righe o il punto di inizio e/o di arresto in un intervallo di righe. In generale, l'utilizzo di una ricerca di indici non cluster è un'operazione perfettamente ragionevole se si restituisce solo una percentuale molto piccola di righe da una tabella. Ma una ricerca non è una buona scelta per una query che restituisce MOLTE righe da una tabella. Quanto è LOTS? Non esiste una risposta semplice, ma se la tua query restituisce più di una piccola percentuale delle righe, assicurati di testare a fondo i suggerimenti dell'indice. A volte una scansione della tabella, o scansione dell'indice cluster, è migliore di una ricerca dell'indice. (Per uno di questi esempi, vedi il mio post sul blog qui).
Strumenti come Pacchetto di ottimizzazione Quest Spotlight può darti ottimi suggerimenti per iniziare il tuo percorso di ottimizzazione con la diagnostica del server SQL, ma più sai come funzionano gli indici di SQL Server e l'ottimizzatore di SQL Server, meglio sarai in grado di valutare quei suggerimenti per le tue query e il tuo dati e possibilmente anche con suggerimenti personali.
Nei seguenti post di questa serie, ti parlerò di altri operatori problematici che potrebbero essere visualizzati nei tuoi piani di query, quindi torna presto!