Perché il mio indice può cercare di stimare il giusto numero di righe e l'operatore di ordinamento non può?


11

Ho una query che utilizza una funzione sul predicato, qualcosa del genere:

commentType = 'EL'
AND commentDateTime >= DATEADD(month,datediff(month,0,getdate()) - 13,0)

Ho un indice filtrato su commentType che ha 40 K righe e quando eseguo la query, il numero stimato di righe per la Ricerca indice è molto preciso (circa 11 K), ma per il passaggio successivo (operatore di ordinamento) ignora completamente le statistiche e stima solo il numero totale di righe nell'indice filtrato.

Perché sta succedendo? Conosco le basi della sargability e ho testato solo per ragioni di sanità mentale sostituendo il dateadd con una data effettiva (01-01-2014) e voilà ... L'ordinamento ha iniziato a indovinare correttamente il numero di righe ...

Perché sta succedendo e come posso risolverlo? Non riesco a passare una data fissa ...


DATEADD(month,datediff(month,0,getdate()) - 13,0)non ha senso per me. Cosa stai cercando di fare con questo? Potrebbe essere migliorato / semplificato?
Daniel Hutmacher,

2
@Daniel Questo è l'inizio del mese, 13 mesi fa.
Aaron Bertrand

1
Inoltre, modifica la domanda per riflettere la versione di SQL Server (?) In cui ti trovi. Usa i tag per quello.
Daniel Hutmacher,

Potresti provare a DATEADD(month, -13, DATEADD(day, 1-DATEPART(day, SYSDATETIME()))vedere se c'è qualche differenza?
Daniel Hutmacher,

Se hai attivato un indice non filtrato (commentType, commentDate), si comporta meglio lì? È solo che a volte gli indici filtrati possono riportare erroneamente le stime in diversi punti dei piani. La stima sembra uscire segnalando il numero totale nell'indice filtrato, ma in realtà è che il piano viene mostrato in modo errato.
Rob Farley,

Risposte:


9

Credo che le tue stime siano errate a causa di un bug dello stimatore che scambia due degli argomenti DATEDIFF. Ne parlo qui:

Una soluzione alternativa è calcolare il primo giorno di 13 mesi fa senza utilizzare DATEDIFF (2008+):

DATEADD(MONTH, -13, DATEADD(DAY, 1-DATEPART(DAY,GETDATE()), CONVERT(DATE, GETDATE()));

Io non sono positivi che affronterà la stima (non ho ancora testato con gli indici filtrati, e io non sono sicuro di quello che il genere è in realtà facendo o perché ha una stima diversa senza il piano e / o il resto della query ).

La correzione che Microsoft consiglia è di utilizzare TF 4199, ma non sono così sicuro che è quello che dovrai fare qui:

Un'altra opzione sarebbe quella di assicurarti di essere sull'ultimo SP / CU assoluto per qualsiasi versione di SQL Server che stai utilizzando, poiché sostengono che sia stato risolto nel seguente articolo KB (anche se ciò richiederà comunque l'uso di TF 4199 a meno che tu non sia nel 2014 o meglio):

La correzione può essere ottenuta con le seguenti build:

(La prossima volta, includi i risultati della SELECT @@VERSIONtua domanda.)

Noterò che l'articolo di KB dice che DATEDIFF può sottovalutare il numero di righe, che è l'opposto di ciò che sta accadendo nel tuo scenario. Ciò non significa che le correzioni non si applichino a te; Penso che la formulazione dell'articolo KB sia imprecisa, poiché le stime possono andare in entrambi i modi a seconda dei dati e dell'intervallo che stai osservando.

Il mio post sul blog sopra ha confermato che lo scambio non si verifica più nel 2014 e fino. Per sicurezza, probabilmente eliminerei DATEDIFF dal tuo predicato e utilizzerei un metodo diverso per calcolare l'inizio del tuo intervallo. Non suggerisco l'overkill di 4199 o l'utilizzo di SQL dinamico per impedire lo scambio errato.


Grazie per l'aiuto ! Ho provato il tuo suggerimento e il piano è cambiato. Ecco com'era prima: s16.postimg.org/t5j6o1yed/fix_wrong.png Ecco come è dopo che ho cambiato il mio dateiff dal tuo: postimg.org/image/5f725rj83 Leggerò tutti gli URL che mi hai dato . Saluti.
MrKudz,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.