In dieser Antwort konzentriere ich mich auf die ursprüngliche Beobachtung:Die von EF generierte Abfrage ist langsam, aber wenn dieselbe Abfrage in SSMS ausgeführt wird, ist sie schnell.
Eine mögliche Erklärung für dieses Verhalten ist Parameter-Sniffing .
Daher generiert EF eine Abfrage mit wenigen Parametern. Wenn Sie diese Abfrage zum ersten Mal ausführen, erstellt der Server einen Ausführungsplan für diese Abfrage unter Verwendung von Parameterwerten, die bei der ersten Ausführung wirksam waren. Dieser Plan ist normalerweise ziemlich gut. Aber später führen Sie dieselbe EF-Abfrage mit anderen Werten für Parameter aus. Es ist möglich, dass für neue Werte von Parametern der zuvor generierte Plan nicht optimal ist und die Abfrage langsam wird. Der Server verwendet weiterhin den vorherigen Plan, da es immer noch dieselbe Abfrage ist, nur die Parameterwerte sind unterschiedlich.
Wenn Sie in diesem Moment den Abfragetext nehmen und versuchen, ihn direkt in SSMS auszuführen, erstellt der Server einen neuen Ausführungsplan, da es sich technisch gesehen nicht um dieselbe Abfrage handelt, die von der EF-Anwendung ausgegeben wird. Schon ein Zeichenunterschied reicht aus, jede Änderung der Sitzungseinstellungen reicht auch aus, damit der Server die Abfrage als neu behandelt. Als Ergebnis hat der Server zwei Pläne für die scheinbar gleiche Abfrage in seinem Cache. Der erste "langsame" Plan ist langsam für die neuen Parameterwerte, da er ursprünglich für andere Parameterwerte erstellt wurde. Der zweite "schnelle" Plan wird für die aktuellen Parameterwerte erstellt, ist also schnell.
Der Artikel Langsam in der Anwendung, schnell in SSMS von Erland Sommarskog erklärt diesen und andere verwandte Bereiche viel ausführlicher.
Es gibt mehrere Möglichkeiten, zwischengespeicherte Pläne zu verwerfen und den Server zu zwingen, sie neu zu generieren. Das Ändern der Tabelle oder das Ändern der Tabellenindizes sollte es tun - es sollte alle Pläne verwerfen, die sich auf diese Tabelle beziehen, sowohl "langsam" als auch "schnell". Dann führen Sie die Abfrage in der EF-Anwendung mit neuen Parameterwerten aus und erhalten einen neuen "schnellen" Plan. Sie führen die Abfrage in SSMS aus und erhalten einen zweiten „schnellen“ Plan mit neuen Parameterwerten. Der Server generiert immer noch zwei Pläne, aber beide Pläne sind jetzt schnell.
Eine andere Variante ist das Hinzufügen von OPTION(RECOMPILE)
zur Abfrage. Mit dieser Option würde der Server den generierten Plan nicht in seinem Cache speichern. Jedes Mal, wenn die Abfrage ausgeführt wird, würde der Server also tatsächliche Parameterwerte verwenden, um den Plan zu generieren, der (er denkt) für die gegebenen Parameterwerte optimal wäre. Der Nachteil ist ein zusätzlicher Aufwand für die Planerstellung.
Allerdings könnte der Server mit dieser Option beispielsweise aufgrund veralteter Statistiken immer noch einen "schlechten" Plan wählen. Aber zumindest wäre Parameter-Sniffing kein Problem.
Diejenigen, die sich fragen, wie man OPTION (RECOMPILE)
hinzufügt Hinweis auf die Abfrage, die von EF generiert wird, sehen Sie sich diese Antwort an:
https://stackoverflow.com/a/26762756/4116017