Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Le prestazioni delle query di Entity Framework differiscono notevolmente con l'esecuzione di SQL non elaborato

In questa risposta mi sto concentrando sull'osservazione originale:la query generata da EF è lenta, ma quando la stessa query viene eseguita in SSMS è veloce.

Una possibile spiegazione di questo comportamento è Sniffing dei parametri .

Quindi, EF genera una query con pochi parametri. La prima volta che si esegue questa query, il server crea un piano di esecuzione per questa query utilizzando i valori dei parametri che erano in vigore nella prima esecuzione. Quel piano di solito è abbastanza buono. Ma in seguito esegui la stessa query EF usando altri valori per i parametri. È possibile che per nuovi valori di parametri il piano precedentemente generato non sia ottimale e la query diventi lenta. Il server continua a utilizzare il piano precedente, perché è sempre la stessa query, solo i valori dei parametri sono diversi.

Se in questo momento prendi il testo della query e provi a eseguirlo direttamente in SSMS, il server creerà un nuovo piano di esecuzione, perché tecnicamente non è la stessa query emessa dall'applicazione EF. Anche una sola differenza di carattere è sufficiente, qualsiasi modifica alle impostazioni della sessione è sufficiente anche affinché il server tratti la query come una nuova. Di conseguenza, il server ha due piani per la query apparentemente identica nella sua cache. Il primo piano "lento" è lento per i nuovi valori dei parametri, poiché è stato originariamente creato per valori di parametro diversi. Il secondo piano "veloce" è costruito per i valori dei parametri correnti, quindi è veloce.

L'articolo Lento nell'applicazione, veloce negli SSMS di Erland Sommarskog spiega questa e altre aree correlate in modo molto più dettagliato.

Esistono diversi modi per eliminare i piani memorizzati nella cache e forzare il server a rigenerarli. La modifica della tabella o la modifica degli indici della tabella dovrebbero farlo:dovrebbero scartare tutti i piani correlati a questa tabella, sia "lento" che "veloce". Quindi esegui la query nell'applicazione EF con nuovi valori di parametri e ottieni un nuovo piano "veloce". Esegui la query in SSMS e ottieni un secondo piano "veloce" con nuovi valori di parametri. Il server genera ancora due piani, ma ora entrambi i piani sono veloci.

Un'altra variante è l'aggiunta di OPTION(RECOMPILE) alla domanda. Con questa opzione il server non memorizzerebbe il piano generato nella sua cache. Pertanto, ogni volta che la query viene eseguita, il server utilizzerà i valori dei parametri effettivi per generare il piano che (ritiene) sarebbe ottimale per i valori dei parametri specificati. Lo svantaggio è un sovraccarico aggiuntivo della generazione del piano.

Intendiamoci, il server potrebbe comunque scegliere un piano "cattivo" con questa opzione a causa di statistiche obsolete, ad esempio. Ma, almeno, lo sniffing dei parametri non sarebbe un problema.

Coloro che si chiedono come aggiungere OPTION (RECOMPILE) suggerimento alla query generata da EF dai un'occhiata a questa risposta:

https://stackoverflow.com/a/26762756/4116017