Ho una query un po 'complessa di SQL Server 2008 (circa 200 righe di SQL abbastanza denso) che non funzionava come avevo bisogno. Nel tempo, le prestazioni sono diminuite da circa 0,5 secondi a circa 2 secondi.
Dando un'occhiata al piano di esecuzione, era abbastanza ovvio che riordinando i join, le prestazioni potevano essere migliorate. L'ho fatto e lo ha fatto ... fino a circa 0,3 secondi. Ora la query ha il suggerimento "OPTION FORCE ORDER" e la vita è buona.
Mi accompagna oggi, ripulendo il database. Archivo circa il 20% delle righe, non eseguendo alcuna azione nel database pertinente tranne l'eliminazione delle righe ... il piano di esecuzione viene TOTALMENTE cancellato . Valuta completamente il numero di righe restituite da alcuni sottotitoli e (ad esempio) sostituisce a:
<Hash>
con
<NestedLoops Optimized='false' WithUnorderedPrefetch='true'>
Ora il tempo di query aumenta da circa 0,3 secondi a circa 18 secondi. (!) Solo perché ho eliminato le righe. Se rimuovo il suggerimento per la query, torno al tempo di query di circa 2 secondi. Meglio, ma peggio.
Ho riprodotto il problema dopo aver ripristinato il database in più posizioni e server. La semplice eliminazione di circa il 20% delle righe da ogni tabella causa sempre questo problema.
- È normale che un ordine di join forzato renda le stime della query completamente imprecise (e quindi tempi di query imprevedibili)?
- Dovrei semplicemente aspettarmi che dovrò accettare prestazioni di query non ottimali o guardarlo come un falco e modificare frequentemente manualmente i suggerimenti per le query? O forse accenni anche a ogni join? .3s a 2s è un grande successo da prendere.
- È ovvio perché l'ottimizzatore è esploso dopo aver eliminato le righe? Ad esempio, "sì, è stata eseguita una scansione di esempio e poiché ho archiviato la maggior parte delle righe in precedenza nella cronologia dei dati, l'esempio ha prodotto risultati scarsi, quindi ha sottovalutato la necessità di un'operazione di hash ordinata"?
Se desideri vedere i piani di esecuzione, ti preghiamo di suggerire un luogo in cui posso pubblicarli. Altrimenti, ho provato il bit più sorprendente. Ecco la stima errata fondamentale, i numeri tra parentesi sono (stimati: effettivi) righe.
/ Clustered Index Scan (908:7229)
Nested Loops (Inner Join) --<
\ NonClustered Index Seek (1:7229)
Si noti che il ciclo interno dovrebbe scansionare 908 righe, ma scansiona invece 52.258.441. Se fosse stato accurato, questo ramo avrebbe funzionato per circa 2ms, anziché 12sec. Prima di eliminare le righe, questa stima del join interno era disattivata solo per un fattore totale di 2 ed è stata eseguita come corrispondenza hash su due indici cluster.