6
votes

Différences de plan de requête SQL Server

J'ai des difficultés à comprendre le comportement des plans de requête estimée pour ma déclaration dans SQL Server lors d'une passer d'une requête paramétrée à une requête non paramétrée.

J'ai la requête suivante: < Pré> xxx

Cette requête est générée par une expression LINQ2SQL et extraite de Linqpad. Cela produit un bon plan de requête (autant que je puisse le dire) et s'exécute dans environ 10 secondes sur la base de données. Cependant, si je remplace les deux utilisations des paramètres avec la valeur exacte, remplacez les deux parties '= @ p0' avec '=' 1fc66e37-6af-4032-B374-e7b60fbd25ea '' Je reçois un plan de requête différent et le La requête fonctionne maintenant beaucoup plus longtemps (plus de 60 secondes, ne l'a-t-elle pas vue).

Pourquoi est-ce que cela effectue le remplacement apparemment innocent produit un plan de requête et une exécution beaucoup moins efficaces? J'ai effacé le cache de procédure avec «DBCC FreeProctacaCaCaCaCaCaCaCACHACCHACCHACE» pour vous assurer que je n'étais pas en cache un mauvais plan, mais le comportement reste.

Mon vrai problème est que je peux vivre avec le temps d'exécution de 10 secondes (à moins pour un bon moment) mais je ne peux pas vivre avec le temps d'exécution de 60 SEC. Ma requête (comme indiqué ci-dessus) par Linq2SQL, il est donc exécuté sur la base de données comme xxx

qui produit le même temps d'exécution médiocre (que je pense est doublement étrange depuis Cela semble utiliser des requêtes paramétrées.

Je ne cherche pas à donner des conseils sur les indices de créer ou d'aimer, j'essaie simplement de comprendre pourquoi le plan de requête et l'exécution sont si dissemblables sur trois apparemment requêtes similaires.

EDIT: J'ai téléchargé des plans d'exécution téléchargés pour la requête non paramétrée et la requête paramétrée ainsi qu'un plan d'exécution pour une requête paramétrée (comme suggéré par Heinz ) avec un autre GUID ici

espère que cela vous aide à m'aider :)


2 commentaires

Pourriez-vous s'il vous plaît poster les plans de requête que vous obtenez? Il suffit d'exécuter définir showplan_text sur Go Sélectionnez ...


Fait ... Ajout du lien vers le plan d'exécution ...


4 Réponses :


1
votes

Je suppose que lorsque vous prenez l'itinéraire non paraméquie, votre DIGR doit être converti d'un VARCHAR en un caractère unique pouvant provoquer un index à ne pas utiliser, alors qu'il sera utilisé en prenant la route paramaturée.

J'ai vu cela arriver à utiliser des requêtes qui ont une petite écoute dans la clause WHERE sur une colonne qui utilise une date d'heure.


0 commentaires

3
votes

Si vous fournissez une valeur explicite, SQL Server peut utiliser des statistiques de ce champ pour créer une décision "meilleure" planification de requête. Malheureusement (comme je me suis vu récemment), si les informations contenues dans les statistiques sont trompeuses, SQL Server fait parfois des choix erronés.

Si vous voulez creuser plus profondément dans ce problème, je vous recommande de vérifier ce qui se passe si vous utilisez d'autres GUID: s'il utilise un plan de requête différent pour différents guidons concrets, c'est une indication selon laquelle les données de statistiques sont utilisées. Dans ce cas, vous voudrez peut-être consulter sp_updaesttats et commandes associées.

EDIT : Jetez un coup d'œil à DBCC Show_statistics : le GUID "lent" et "rapide" sont probablement dans différents seaux dans l'histogramme. J'ai eu un problème similaire < / a>, que j'ai résolu en ajoutant un index Table indique sur SQL, qui "guide" SQL Server vers la recherche du plan de requête "Droite". Fondamentalement, j'ai examiné quels indices sont utilisés lors d'une requête "rapide" et des codés dur à ceux de la SQL. Ceci est loin d'une solution optimale ou élégante, mais je n'ai pas encore trouvé un meilleur ...


3 commentaires

Je viens d'essayer d'exécuter le lent, non paramétré avec un autre GUID et il a produit un bon plan de requête et exécuté comme prévu. Pourriez-vous peut-être élaborer sur ce que je dois rechercher en ce qui concerne les statistiques? Est-ce un indice spécifique qui doit être reconstitué ou similaire?


Certes, mon premier regard sur la DBBC Show_Statistics, mais je semble déchiffrer que les GUID sont dans des seaux séparés (le "lent" avec de la plage_aux égaux à 316 et le "rapide" avec plage_aux égal à 0 (?)). Malheureusement, j'utilise Linq2SQL, donc je n'ai aucun chemin réel pour définir des indemnités de requête. Puis-je recalculer des statistiques en quelque sorte?


Oui, les statistiques de mise à jour et SP_UPDATESTS devraient le faire.



0
votes

c'est difficile à dire sans regarder les plans d'exécution , cependant, si j'allais deviner à une raison je dirais que c'est une combinaison de paramètres reniflant et de faibles statistiques - dans le cas où Vous codez sur le GUID dans la requête, l'optimiseur de requête tente d'optimiser la requête pour cette valeur du paramètre. Je crois que la même chose se passe avec la requête paramétré / préparée (ceci s'appelle le paramètre reniflant - le plan d'exécution est optimisé pour les paramètres utilisés pour la première fois que l'instruction préparée est exécutée), mais cela ne se produit certainement pas lorsque vous déclarez le paramètre et utilisez-le dans la requête.

Comme je l'ai dit, SQL Server tente d'optimiser le plan d'exécution pour cette valeur, et il faut donc généralement voir de meilleurs résultats. Il semble que cette information fondamentale de ses décisions est incorrecte / trompeuse, et vous êtes meilleur (pour une certaine raison) lorsqu'il optimise la requête d'une valeur de paramètre générique.

Ceci est surtout hypothèse, mais il est impossible de dire vraiment sans l'exécution - si vous pouvez télécharger le plan d'exécution quelque part, je suis sûr que quelqu'un sera capable de vous aider avec la vraie raison.


0 commentaires

2
votes

Je ne cherche pas de conseiller sur quels indices à créer ou à similaires, j'essaie simplement de comprendre pourquoi le plan de requête et l'exécution sont si dissemblables sur trois requêtes apparemment similaires.

Vous semblez avoir deux index: xxx

Le premier index ne couvre pas cookieid mais est commandé sur Servertime et donc est plus efficace pour le moins ProductID S (c.-à-d. Ceux que vous avez beaucoup)

Le deuxième indice couvre toutes les colonnes mais n'est pas commandé, et donc est plus efficace pour plus sélectif ProductID 's (ceux que vous avez peu).

en moyenne, vous ProductID La cardinalité est de sorte que SQL Server attend que la deuxième méthode soit efficace, ce qu'il utilise lorsque vous utilisez des requêtes paramétrisées ou fournissez explicitement un fichier sélectif ' s.

Cependant, votre adresse Original est considérée comme moins sélective, c'est pourquoi la première méthode est utilisée.

Malheureusement, la première méthode nécessite un filtrage supplémentaire sur CookieID C'est pourquoi il est moins efficace.


1 commentaires

Ahh ... Peut-être que cela explique également pourquoi je reçois l'exécution "rapide" si je retire les parties redondantes de la clause WHERE (les parties ou les pièces qui vérifient sont NULL sont redondantes) car aucun filtrage supplémentaire n'est alors requis sur le cookieid. La requête est générée via LINQ2SQL à je ne peux pas vraiment modifier, mais je vérifierai si je peux faire la colonne non-NULL qui semble supprimer les clauses additionnelles et générer la requête rapide.