Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Les performances des requêtes Entity Framework diffèrent extrêmement avec l'exécution SQL brute

Dans cette réponse, je me concentre sur l'observation initiale :la requête générée par EF est lente, mais lorsque la même requête est exécutée dans SSMS, elle est rapide.

Une explication possible de ce comportement est Renifleur de paramètres .

Ainsi, EF génère une requête qui a peu de paramètres. La première fois que vous exécutez cette requête, le serveur crée un plan d'exécution pour cette requête en utilisant les valeurs des paramètres qui étaient en vigueur lors de la première exécution. Ce plan est généralement assez bon. Mais, plus tard, vous exécutez la même requête EF en utilisant d'autres valeurs pour les paramètres. Il est possible que pour de nouvelles valeurs de paramètres le plan précédemment généré ne soit pas optimal et la requête devienne lente. Le serveur continue d'utiliser le plan précédent, car il s'agit toujours de la même requête, seules les valeurs des paramètres sont différentes.

Si à ce moment vous prenez le texte de la requête et essayez de l'exécuter directement dans SSMS, le serveur créera un nouveau plan d'exécution, car techniquement ce n'est pas la même requête qui est émise par l'application EF. Même une différence de caractère suffit, tout changement dans les paramètres de session est également suffisant pour que le serveur traite la requête comme une nouvelle. En conséquence, le serveur a deux plans pour la même requête apparemment dans son cache. Le premier plan "lent" est lent pour les nouvelles valeurs de paramètres, car il a été construit à l'origine pour des valeurs de paramètres différentes. Le deuxième plan "rapide" est construit pour les valeurs de paramètres actuelles, il est donc rapide.

L'article Lent dans l'application, rapide dans SSMS par Erland Sommarskog explique cela et d'autres domaines connexes de manière beaucoup plus détaillée.

Il existe plusieurs façons de supprimer les plans mis en cache et de forcer le serveur à les régénérer. Changer la table ou changer les index de table devrait le faire - cela devrait supprimer tous les plans liés à cette table, à la fois "lents" et "rapides". Ensuite, vous exécutez la requête dans l'application EF avec de nouvelles valeurs de paramètres et obtenez un nouveau plan "rapide". Vous exécutez la requête dans SSMS et obtenez un deuxième plan "rapide" avec de nouvelles valeurs de paramètres. Le serveur génère toujours deux plans, mais les deux plans sont rapides maintenant.

Une autre variante consiste à ajouter OPTION(RECOMPILE) à la requête. Avec cette option, le serveur ne stockerait pas le plan généré dans son cache. Ainsi, chaque fois que la requête s'exécute, le serveur utilise les valeurs de paramètre réelles pour générer le plan qui (il pense) serait optimal pour les valeurs de paramètre données. L'inconvénient est une surcharge supplémentaire de la génération du plan.

Attention, le serveur peut toujours choisir un "mauvais" plan avec cette option en raison de statistiques obsolètes, par exemple. Mais, au moins, le reniflage des paramètres ne serait pas un problème.

Ceux qui se demandent comment ajouter OPTION (RECOMPILE) indice de la requête générée par EF, jetez un œil à cette réponse :

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