Unisco una tabella piccola (1.000 righe) a una tabella grande (8 milioni di righe) in SQL Server 2008. Il join utilizza un indice di copertura non cluster sulla tabella grande e il join può produrre tre possibili piani di query. Sto cercando di capire quale piano è meglio, ma voglio anche generalizzare questa conoscenza, così la prossima volta posso sapere meglio quale euristica usare quando guardo le statistiche di I / O SQL.
Il piano n. 1 è un loop loop ed emette statistiche per la tabella di grandi dimensioni in questo modo:
Scan count 2582, logical reads 35686, physical reads 1041, read-ahead reads 23052
Il piano n. 2 è un join unione ed emette statistiche come questa:
Scan count 1, logical reads 59034, physical reads 49, read-ahead reads 59004
Il piano n. 3 è un hash join ed emette statistiche come questa:
Scan count 3, logical reads 59011, physical reads 5, read-ahead reads 59010
L'indice di copertura è ordinato per (ID, Date)
. La query restituisce dati per circa il 50% degli ID e, per ciascun ID, restituisce una parte contigua degli ultimi 3 mesi di dati, che di solito è circa 1/4 o le righe per ciascun ID. La query restituisce circa 1/8 delle righe totali nell'indice. In altre parole, la query è scarsa ma coerente.
La mia ipotesi è che il piano n. 1 sia terribile per questo carico di lavoro, perché spostare la testina del disco circa 2.500 volte (o anche 1.041 volte) è molto più costoso di una scansione sequenziale del disco. Suppongo anche che # 3 e # 2 abbiano modelli I / O simili, sequenziali (e quindi più efficienti).
Ma c'è un caso in cui il piano n. 1 è davvero il migliore, in cui "migliore" significa meno impatto sul sottosistema I / O e meno impatto su altre query in esecuzione contemporaneamente?
O dipende davvero da molte variabili come il tipo di sottosistema del disco che ho, la frammentazione dell'indice, ecc. Se "dipende" ci sono delle regole pratiche per affrontare il problema?