J'essaie de comprendre un problème que nous rencontrons avec SQL Server 2000. Nous sommes un site Web modérément transactionnel et nous avons un proc stocké appelé sp_GetCurrentTransactions
qui accepte un identifiant client et deux dates.
Maintenant, selon les dates et le client, cette requête peut renvoyer n'importe quoi de zéro à des milliers de lignes.
Le problème: ce que nous avons vécu, c'est que nous obtiendrons soudainement un certain nombre d'erreurs (généralement Execution Timeout Expired
ou similaires) pour un client particulier pendant qu'il essaie d'exécuter ce processus stocké. Nous examinons donc la requête, l'exécutons dans SSMS et constatons qu'elle prend 30 secondes. Nous recompilons donc le proc stocké et -bang- il fonctionne maintenant en 300 ms.
J'en ai parlé à notre DBA. Il m'a dit que la base de données a créé un plan de requête lorsque nous avons créé le proc stocké. Il a dit que c'était un bon plan pour cet ensemble de paramètres, mais si vous y jetez un certain ensemble de paramètres, alors le plan ne sera pas le meilleur plan pour ces données, et donc vous le verrez fonctionner lentement.
Les options qui me sont présentées sont le déplacement de cette requête problématique à partir d'un proc stocké et le retour dans SQL dynamique qui a son plan d'exécution créé à chaque exécution.
Cela me semble être un pas en arrière et j'ai l'impression qu'il doit y avoir un moyen de contourner cela. Existe-t-il un autre moyen de résoudre ce problème?
Toutes les réponses sont appréciées.
la source
Réponses:
Ce problème est appelé reniflement des paramètres.
Les versions ultérieures de SQL Server vous offrent plus d'options pour y faire face, comme
OPTION (RECOMPILE)
ou desOPTIMIZE FOR
conseils.Vous pouvez essayer de déclarer des variables dans la procédure stockée, d'affecter les valeurs des paramètres aux variables et d'utiliser les variables à la place des paramètres, comme si la plupart du temps vous obtenez un plan raisonnablement satisfaisant.
Normalement, les plans les plus catastrophiques sont ceux qui sont compilés pour des paramètres avec une sélectivité très élevée, mais exécutés avec des paramètres avec une sélectivité faible.
En supposant que le plan généré est plus robuste avec cette approche et satisfaisant pour toutes les valeurs de paramètres, l'avantage de cette approche par rapport à celle suggérée par JNK est qu'elle n'entraîne pas de coût de compilation pour chaque appel.
L'inconvénient est que pour certaines exécutions, le temps d'exécution peut être supérieur à celui d'un plan spécialement conçu pour ces valeurs de paramètre, il s'agit donc d'un compromis entre le temps de compilation et le temps d'exécution.
la source
Au lieu d'utiliser du SQL dynamique, vous pouvez toujours simplement changer vos appels de proc en:
EXEC Database.dbo.usp_Myprocedure 'Parameter' WITH RECOMPILE
le
WITH RECOMPILE
forces (vous l'avez deviné!) Recompilent le plan d'exécution à chaque exécution.Vous pouvez également inclure
WITH RECOMPILE
dans la définition du proc stocké:la source
Vous pouvez également essayer de décider pour la base de données quel plan utiliser, bien que vous vous battiez un peu avec l'optimiseur, il est donc plus fragile que vous ne l'espérez.
La technique est la suivante: divisez la procédure stockée en 2, l'une destinée à un ensemble de paramètres, l'autre à l'autre. Ajoutez des clauses where à chacune de sorte qu’entre elles, elles couvrent tous les cas possibles. Regardez les plans de requête - l'un doit être optimisé pour un ensemble de paramètres, l'autre pour l'autre ensemble. Vous devrez peut-être bricoler la requête pour que cela se produise, ou cela peut ne pas être possible pour votre requête, auquel cas cette approche ne fonctionnera pas.
Faites maintenant vérifier la valeur stockée de votre procédure stockée d'origine et envoyez-la à l'une des deux procédures stockées appropriées du paragraphe précédent.
Cela peut fonctionner, mais c'est une sorte de piratage pour forcer l'optimiseur à fonctionner plus efficacement pour votre requête. Comme tous ces hacks, dans les futures versions de la base de données, cela pourrait être inutile ou même aggraver les choses. Donc, même si cela fonctionne, vous devez décider si cela en vaut la peine.
la source
Vous pouvez aussi essayer
SET FORCEPLAN
indexer les astuces.http://msdn.microsoft.com/en-us/library/ms188344.aspx
Il vous permet essentiellement de choisir l'ordre dans lequel la jointure se produit.
Vous pouvez avoir des indices d'index pour vous assurer que SQL Server utilise les index corrects.
la source
Hmmm ... si nous nous concentrons uniquement sur cette procédure stockée, je serais surpris que l'utilisation du plan d'exécution mis en cache soit à l'origine du problème que vous voyez. Je demanderais à voir le plan d'exécution de la procédure stockée en utilisant un ensemble de paramètres pour le client et les deux dates. Je me demande si un index plus spécifique serait utile -> comme sur customerId, et les deux dates seulement?
la source
La dégradation soudaine des performances ressemble à un plan de requête inefficace qui est produit, probablement en raison de statistiques manquantes. Exécutez un profileur SQL Server avec les catégories d'événements "Erreurs et avertissements" définies et voyez s'il existe des avertissements concernant les statistiques manquantes.
Un index peut également vous manquer, ou vous devrez peut-être défragmenter les index car ils peuvent être trop fragmentés pour être utilisés par SQL Server, ce qui fait penser qu'un scan de table produira moins d'E / S.
@JNK soulève un grand point sur les proc stockés - ceux-ci sont compilés à l'avance et le plan de requête sera stocké avec la procédure stockée.
Je ne suis pas nécessairement d'accord avec l'utilisation de WITH RECOMPILE car vous perdez alors l'avantage du plan de requête stocké et réutilisé. Il y a des cas où cela est nécessaire - c'est-à-dire si vos statistiques de distribution dans les tables sous-jacentes diffèrent considérablement entre les appels, mais généralement, une fois que les données dans les tables sont arrivées à maturité, la distribution des données dans les tables variera de manière minimale.
Donc, pour résumer:
la source