Il y a quelque temps, une requête m'avait posé beaucoup de questions pour l'un de mes utilisateurs. Il était encore en train d'évoluer et d'être peaufiné, mais finalement il s'est stabilisé et a fonctionné assez rapidement. Nous avons donc créé une procédure stockée à partir de celle-ci.
Jusqu'ici, si normal.
La procédure stockée, cependant, était lente. Aucune différence matérielle entre la requête et le proc, mais le changement de vitesse était énorme.
[Arrière-plan, nous utilisons SQL Server 2005.]
Un administrateur de base de données local et sympathique (qui ne travaille plus ici) a jeté un coup d’œil à la procédure mémorisée et a déclaré «paramétrage». ( Edit: bien qu'il semble que cela soit peut-être aussi connu sous le nom de «paramètre reniflant», ce qui pourrait expliquer la rareté des hits de Google lorsque j'ai essayé de le rechercher.)
Nous avons résumé une partie de la procédure stockée en une seconde, intégré l'appel externe à la procédure externe préexistante, appelée la procédure externe prédéfinie, et hop, c'était aussi rapide que la requête d'origine.
Alors, qu'est-ce qui donne? Quelqu'un peut-il expliquer l'usurpation de paramètre?
Bonus de crédit pour
Pour votre information - vous devez savoir quelque chose d’autre lorsque vous travaillez avec SQL 2005 et que des procs sont stockés avec des paramètres.
SQL Server compilera le plan d'exécution du processus stocké avec le premier paramètre utilisé. Donc si vous lancez ceci:
usp_QueryMyDataByState 'Rhode Island'
Le plan d'exécution fonctionnera mieux avec les données d'un petit État. Mais si quelqu'un se retourne et court:
usp_QueryMyDataByState 'Texas'
Le plan d'exécution conçu pour les données de la taille de Rhode-Island risque de ne pas être aussi efficace que celui des données de la taille du Texas. Cela peut produire des résultats surprenants au redémarrage du serveur, car le plan d'exécution nouvellement généré sera ciblé sur le paramètre utilisé en premier - pas nécessairement le meilleur. Le plan ne sera pas recompilé tant qu'il n'y aura pas de raison de le faire, comme si les statistiques étaient reconstruites.
C’est là que les plans de requête entrent en jeu et que SQL Server 2008 offre de nombreuses nouvelles fonctionnalités qui aident les administrateurs de base de données à identifier un plan de requête particulier à long terme, quels que soient les paramètres appelés en premier.
Mon souci est que lorsque vous avez reconstruit votre proc stocké, vous avez forcé le plan d'exécution à recompiler. Vous l'avez appelé avec votre paramètre préféré, et bien sûr, c'était rapide - mais le problème n'était peut-être pas la procédure stockée. Il se peut que le processus stocké ait été recompilé à un moment donné avec un ensemble de paramètres inhabituel et donc un plan de requête inefficace. Il se peut que vous n'ayez rien corrigé et que vous rencontriez le même problème lors du prochain redémarrage du serveur ou de la recompilation du plan de requête.
Oui, je pense que vous voulez dire le reniflement des paramètres, technique utilisée par l'optimiseur SQL Server pour tenter de déterminer les valeurs/plages de paramètres afin de choisir le meilleur plan d'exécution pour votre requête. Dans certains cas, SQL Server effectue un travail médiocre en matière de détection de paramètre et ne sélectionne pas le meilleur plan d'exécution pour la requête.
Je crois que cet article de blog http://blogs.msdn.com/queryoptteam/archive/2006/03/31/565991.aspx a une bonne explication.
Il semble que le DBA de votre exemple ait choisi l'option n ° 4 pour déplacer la requête vers un autre sproc vers un contexte procédural distinct.
Vous auriez pu également utiliser le avec recompiler sur le sproc d'origine ou l'option optimiser pour sur le paramètre.
Un moyen simple d'accélérer ce processus consiste à réaffecter les paramètres d'entrée aux paramètres locaux au tout début du sproc, par ex.
CREATE PROCEDURE uspParameterSniffingAvoidance
@SniffedFormalParameter int
AS
BEGIN
DECLARE @SniffAvoidingLocalParameter int
SET @SniffAvoidingLocalParameter = @SniffedFormalParameter
--Work w/ @SniffAvoidingLocalParameter in sproc body
-- ...
D'après mon expérience, la meilleure solution pour la détection de paramètres est le 'SQL dynamique'. Il est important de noter que 1. vous devez utiliser des paramètres dans votre requête SQL dynamique. 2. Vous devez utiliser sp_executesql (et non sp_execute), qui enregistre le plan d'exécution pour chaque valeur de paramètre.
La détection de paramètre est une technique utilisée par SQL Server pour optimiser le plan d'exécution de la requête pour une procédure stockée. Lorsque vous appelez la procédure stockée pour la première fois, SQL Server examine les valeurs de paramètre données de votre appel et décide des index à utiliser en fonction des valeurs de paramètre.
Ainsi, lorsque le premier appel contient des paramètres peu typiques, SQL Server peut sélectionner et stocker un plan d'exécution sous-optimal en ce qui concerne les appels suivants de la procédure stockée.
Vous pouvez contourner ce problème soit par
WITH RECOMPILE
J'ai même entendu dire qu'il est préférable de ne pas utiliser de procédures stockées du tout, mais d'envoyer vos requêtes directement au serveur ... J'ai récemment rencontré le même problème où je n'ai pas encore de solution réelle ... vars locaux aide à retrouver le bon plan d'exécution. Pour certaines requêtes, les performances se dégradent avec les vars locaux.
Je dois encore faire plus de recherches sur la manière dont SQL Server met en cache et réutilise les plans d'exécution (sous-optimaux).
J'ai eu le même problème. Le plan d'exécution de ma procédure stockée a pris 30 à 40 secondes. J'ai essayé d'utiliser les instructions SP dans la fenêtre de requête et il a fallu quelques ms pour exécuter la même chose. Ensuite, j'ai élaboré la déclaration des variables locales dans la procédure stockée et le transfert des valeurs des paramètres vers les variables locales. Cela a rendu l'exécution de SP très rapide et maintenant, le même SP s'exécute en quelques millisecondes au lieu de 30 à 40 secondes.