Le code crée un plan différent lorsqu'il est exécuté de manière ad hoc ou dans une procédure stockée

9

J'ai une instruction de suppression qui utilise un mauvais plan lorsqu'elle est exécutée dans une procédure stockée, mais choisit un bien meilleur plan lorsqu'elle est exécutée ad hoc.

J'ai reconstruit tous les index des tables utilisées par la requête et supprimé tous les caches. L'optimiseur choisit toujours le mauvais plan pour la procédure stockée.

Je voudrais savoir pourquoi l'optimiseur utilise un plan d'exécution différent pour la procédure stockée par rapport au SQL ad hoc.

MISE À JOUR: Je suppose que ce doit être les paramètres après tout - quand j'ai exécuté le code ad-hoc avec la variable codée en dur, je peux obtenir le "mauvais" plan avec la bonne valeur (c'est une date, des valeurs qui ont un an semblent générer le "bon" plan). Maintenant, essayons de forcer le "bon" plan sur le proc en utilisant un indice de requête.

SOLUTION: J'ai fini par obtenir le plan que je voulais en utilisant le conseil OPTIMISER POUR INCONNU.

msgisme
la source
C'est probablement le reniflement des paramètres . La requête fait-elle référence à une variable dans sa WHEREclause?
Nick Chammas
4
Pouvez-vous ajouter du code s'il vous plaît
gbn
Affichez également les plans quelque part, s'il vous plaît. En l'état, il va être assez difficile de vous dire exactement pourquoi les plans sont différents.
Aaron Bertrand
OK, plus d'informations: je ne peux pas publier les plans et les codes avant de les avoir un peu obscurcis. Je vais essayer de les relever dans quelques-uns. Le plan de la procédure stockée (mauvais) effectue une analyse d'index en cluster d'une grande table (l'ensemble, toutes les partitions). Il utilise ensuite une boucle pour rechercher des lignes dans une petite table, puis supprime de la petite table.
msgisme
Le plan pour le code ad hoc (bon) effectue une analyse de la table de la petite table (qui n'a que 5 à 10 lignes) et utilise un index non clusterisé de la grande table pour trouver les lignes dont il a besoin pour vérifier dans le PK de la grande table. J'essaierai d'obtenir les plans réels dès que possible.
msgisme

Réponses:

5

Les suspects habituels:

  1. constantes dans adhoc, paramètres dans le code
  2. incompatibilité des types de données dans le code
  3. reniflement des paramètres

Point 1: l'optimiseur peut choisir le meilleur plan pour les constantes.
Changer les constantes = changer le plan. Un plénum paramétré est réutilisable

Le point 2 introduira des conversions implicites en raison de la priorité du type de données,
par exemple la colonne varchar par rapport au paramètre nvarchar

Point 3: utiliser le masquage des paramètres ou OPTIMISER POUR INCONNU
Modifier: Pour tester: exécuter le proc stocké, exécuter sp_updatestats, réexécuter. Cela invalidera les plans mis en cache, ce qui est mieux que de vider le cache du plan

Edit: après le commentaire de jcolebrand

Vous pouvez désactiver le reniflement de plusieurs manières. Les 3 principaux sont

  • RECOMPILE. C'est idiot IMO.
  • OPTIMISER (sic) POUR INCONNU
  • Masquage des paramètres

Masquage des paramètres:

DECLARE @MaskedParam varchar(10)
SELECT @MaskedParam = @SignaureParam

SELECT...WHERE column = @MaskedParam

Le masquage et l'indice OPTIMIZE ont le même effet (peut-être pour des raisons différentes). Autrement dit, l'optimiseur doit utiliser des statistiques et la distribution des données ( Remarque: toujours en cours de test par Mark Storey-Smith ) évaluer les paramètres sur leurs propres mérites ? , plutôt que ce qu'ils étaient lors du dernier appel. L'optimiseur peut recompiler ou non. SQL Server 2005 a ajouté une recompilation au niveau des instructions afin qu'il y ait moins d'impact

Maintenant, pourquoi un plan avec des paramètres "reniflés" est "collant" par rapport aux paramètres masqués / "inconnus", je ne suis pas sûr.

J'ai utilisé le masquage des paramètres depuis SQL Server 2000 pour tout sauf le code le plus simple. J'ai remarqué que cela pouvait se produire avec un code plus complexe. Et à mon ancien travail, j'ai quelques rapports procs que je pouvais changer les valeurs par défaut des paramètres du plan. Je pense que l'approche "culte du fret" était plus facile qu'un appel de support.

Edit 2, 12 oct 2011, après quelques discussions

  • Le masquage des paramètres et OPTIMISER POUR INCONNU ont le même effet pour autant que je sache.
    L'astuce est plus propre que le masquage mais a été ajoutée avec SQL Server 2008.

  • Le reniflage des paramètres se produit au moment de la compilation.
    WITH RECOMPILE génère un nouveau plan à chaque exécution. Cela signifie qu'un mauvais choix de valeurs par défaut influencera le plan. Lors de mon dernier travail, j'ai pu le démontrer facilement avec du code de rapport: la modification des valeurs par défaut des paramètres a modifié le plan indépendamment des paramètres fournis.

  • Cet article MS Connect est intéressant: utilisation d'index sous-optimale dans la procédure stockée (mentionnée dans l'une des réponses SO ci-dessous)

  • Bob Beauchemin le mentionne aussi

Problèmes en suspens

  • Le reniflement s'applique-t-il toujours à WITH RECOMPILE? Autrement dit, si l'optimiseur sait rejeter le plan, vise-t-il à le réutiliser?

  • Pourquoi les plans reniflés sont-ils "collants"?

Liens depuis SO:

gbn
la source
1. Le paramètre dans le sp est une variable dans le code 2. Encore une fois, le même type de données 3. J'ai exécuté les deux avec une grande variété de paramètres et j'obtiens le même plan à chaque fois. J'ai vidé le cache après chaque tentative.
msgisme
1
Re: point 3. Vous pouvez également exécuter l'instruction avec OPTION (RECOMPILE)ou l'ensemble du processus WITH RECOMPILEpour forcer SQL Server à ignorer les plans existants.
Nick Chammas
3
BTW c'est OPTIMIZEparce que Microsoft est une entreprise américaine. :)
Nick Chammas
1
@Gbn des réflexions sur la prévention / la suppression du reniflement de paramètres?
jcolebrand
1
@jcolebrand: la réponse simple est "non" :-)
gbn
2

N'oubliez pas que les paramètres ANSI que vous avez configurés pour le plan de connexion jouent un rôle dans la sélection du plan d'exécution. Lorsque l'application appelle la procédure stockée, elle a probablement des paramètres ANSI différents de votre connexion SSMS.

mrdenny
la source