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

Composants internes de SQL Server :plan de mise en cache Pt. II – Plans de recompilation

Ceci fait partie d'une série sur la mise en cache du plan interne de SQL Server. Assurez-vous de lire le premier message de Kalen sur ce sujet.

SQL Server existe depuis plus de 30 ans, et je travaille avec SQL Server depuis presque aussi longtemps. J'ai vu beaucoup de changements au fil des années (et des décennies !) et des versions de cet incroyable produit. Dans ces articles, je vais partager avec vous comment j'examine certaines des fonctionnalités ou certains aspects de SQL Server, parfois avec un peu de perspective historique

Dans mon article précédent , j'ai parlé des diagnostics du serveur SQL, y compris les différentes options dont dispose SQL Server pour réutiliser un plan de requête. Nous avons examiné trois types de plans de requête :ad hoc, préparé et de procédure. J'ai terminé la discussion en examinant une réutilisation inappropriée d'un plan, qui peut se produire lorsque SQL Server applique le reniflage de paramètres dans les mauvaises situations. Si un plan est basé sur une valeur initiale qui amène l'optimiseur à générer un plan approprié pour cette valeur, puis que le même plan est utilisé pour une valeur différente, le plan peut ne plus être optimal.

Alors, que pouvons-nous faire lorsque le reniflage de paramètres est un problème ? Nous pouvons forcer SQL Server à proposer un nouveau plan. Habituellement, nous appelons l'acte de proposer un nouveau plan "recompilation", mais cela devrait probablement s'appeler "réoptimisation". Cependant, la plupart des gens utilisent le terme "recompiler", c'est donc ce que j'utiliserai ici.

Si une utilisation inappropriée du reniflage de paramètres pose un problème, une solution simple consiste simplement à dire à SQL Server de proposer un nouveau plan. Pour les instructions individuelles, comme avec les plans PREPARED qui ont été paramétrés automatiquement, nous pouvons ajouter l'indicateur RECOMPILE à une requête. En utilisant FORCED paramétré (discuté dans l'article précédent), cette requête sera paramétrée.

SELECT * FROM dbo.newsales 
WHERE SalesOrderID < @num;

Si nous voulons nous assurer que nous obtenons un nouveau plan à chaque fois que nous exécutons cette requête, avec des valeurs potentiellement très différentes pour @num, nous pouvons ajouter l'indicateur RECOMPILE comme indiqué :

SELECT * FROM dbo.newsales
  WHERE SalesOrderID < @num
OPTION (RECOMPILE);

Pour les procédures stockées, nous avons trois options. Tout d'abord, nous pouvons vérifier si la recompilation améliorera réellement les performances en exécutant la procédure avec l'option RECOMPILE :

EXEC get_sales_range 66666 WITH RECOMPILE;

Cette option entraînera la génération d'un nouveau plan uniquement pour cette exécution. Il ne sera pas sauvegardé et ne sera certainement pas réutilisé. La valeur usecount affichée dans sp_cacheobjects (décrite dans le post précédent) pour la procédure n'augmentera pas puisque le plan d'origine n'est pas réutilisé.

Deuxièmement, si nous trouvons que l'exécution de WITH RECOMPILE aide, nous pourrions envisager de recréer la procédure avec l'option RECOMPILE, auquel cas elle ne réutilisera jamais le plan et la procédure n'apparaîtra pas du tout dans le cache du plan.

DROP PROC IF EXISTS get_sales_range;GO
CREATE PROC get_sales_range
   @num int
WITH RECOMPILE
AS
    SELECT * FROM dbo.newsales
    WHERE SalesOrderID < @num;
GO

Pour ma petite procédure simple, l'utilisation de l'option WITH RECOMPILE pour l'ensemble de la procédure peut avoir un sens. Mais si la procédure est plus complexe, il n'est peut-être pas judicieux de recompiler l'intégralité de la procédure car une instruction pose problème. Ainsi, la troisième option consiste à utiliser l'indicateur RECOMPILE pour une instruction dans la procédure, donc cela ressemble à ceci :

DROP PROC IF EXISTS get_sales_range;
GO
CREATE PROC get_sales_range
   @num int
AS
    SELECT * FROM dbo.newsales
    WHERE SalesOrderID < @num
    OPTION (RECOMPILE);
GO

L'utilisation de l'une de ces options RECOMPILE peut forcer SQL Server à proposer un nouveau plan à votre demande. Maintenant, nous allons regarder quand vos diagnostics SQL Server proposent un nouveau plan lorsque vous ne le demandez pas, c'est-à-dire quand la recompilation automatique d'un plan existant se produit-elle ?


La recompilation automatique d'un plan se produit dans deux types de situations :

  • Tout d'abord, si l'optimiseur détermine que le plan existant n'est plus correct, généralement en raison d'une modification des définitions d'objet, il devra proposer un nouveau plan. Par exemple, si vous avez un plan pour une requête qui sélectionne à partir de TableA, et que vous supprimez ensuite plusieurs colonnes ou modifiez les types de données des colonnes dans TableA, SQL Server recompilera la requête pour proposer un plan qui reflète les modifications DDL.
  • La deuxième situation dans laquelle la recompilation automatique se produit est lorsque SQL Server détermine que le plan n'est peut-être plus optimal, en raison d'une modification des statistiques. Dans la plupart des cas, si les statistiques sur l'une des colonnes ou des index ont été mises à jour depuis la dernière fois que le plan a été compilé, il sera recompilé. Mais cela conduit à une autre question. Quand les statistiques sont-elles mises à jour ? Les statistiques peuvent être automatiquement mises à jour lorsqu'un nombre suffisant de lignes dans les colonnes pertinentes ont été modifiées. Combien est-ce suffisant ? On en parle sous peu.

Par défaut, SQL Server mettra automatiquement à jour les statistiques en raison d'une option de base de données activée par défaut. Mais si vous êtes propriétaire d'une base de données (ou un "sa" SQL, qui apparaît comme propriétaire dans chaque base de données), vous pouvez modifier les options. L'une des options s'appelle AUTO_UPDATE_STATISTICS et une autre s'appelle AUTO_UPDATE_STATISTICS_ASYNC. L'option AUTO_UPDATE_STATISTICS est activée dans la base de données tempdb, donc chaque nouvelle base de données hérite de cette option. Lorsque cette option est activée et que le moteur d'exécution de la requête détecte des modifications sur un nombre suffisant de lignes pendant le traitement d'une requête, l'exécution s'interrompt pendant la mise à jour des statistiques, puis la requête est recompilée. L'autre option, AUTO_UPDATE_STATISTICS_ASYNC, peut potentiellement avoir moins d'effet sur le temps d'exécution de la requête car l'exécution ne s'interrompt pas, au prix de l'utilisation d'un éventuel plan sous-optimal. Avec la deuxième option, si le moteur d'exécution détecte un besoin de mettre à jour les statistiques, un thread d'arrière-plan est déclenché pour effectuer la mise à jour, et le thread principal continue d'exécuter la requête avec les statistiques d'origine et le plan d'origine. La prochaine requête qui accède aux tables affectées et voit les statistiques mises à jour recompilera la requête, mais elle ne s'arrêtera pas et ne mettra pas à jour les statistiques au milieu de l'exécution.

Il y a quelques autres situations ainsi que des conseils de requête qui contrôlent si les plans sont recompilés ou non, donc je vais vous montrer un organigramme que je partagerai avec vous un organigramme que j'ai créé pour mes cours de formation sur les composants internes de SQL Server.

La flèche est l'endroit où SQL Server commence à traiter votre lot. Il vérifie d'abord s'il existe déjà un plan pour votre lot dans le cache, et si la réponse est NON, suit la flèche vers la droite et compile un plan. Le plan est mis en cache, puis SQL Server redémarre. Oui, le plan devrait être en cache cette fois, donc il suit la flèche vers le bas et demande si un indice appelé KEEP PLAN a été utilisé. Si OUI, SQL Server démarre immédiatement l'exécution du plan et n'effectue aucune autre vérification.

La question suivante est de savoir si des modifications DDL ont été apportées. Si non, il pose des questions sur plusieurs autres situations dont je ne pourrai pas parler dans cet article. En fait, je ne vais vraiment pas passer en revue toutes les options ici. Je vous laisse cela. Mais si vous avez des questions ou des confusions, n'hésitez pas à les poser dans la section des commentaires ici, ou à me tweeter à @sqlqueen. Je soulignerai la question à l'extrême droite :est-ce que AUTO_STATS_ASYNC est activé ? Ici, vous pouvez voir que si la réponse est OUI, il y a deux actions. Une branche commence juste l'exécution avec le plan existant, et l'autre est le fil d'arrière-plan qui met à jour les statistiques mais ne fait rien d'autre. La prochaine requête rencontrera la boîte de décision au milieu "De nouvelles statistiques sont-elles disponibles" et devrait répondre OUI, donc la requête sera recompilée.

La seule autre chose dont je parlerai est la question « Y a-t-il des statistiques obsolètes ? » Cela signifie essentiellement que les statistiques sont obsolètes car trop de modifications ont été apportées. Alors maintenant, nous pouvons parler de combien c'est trop.

Bien qu'il existe différentes valeurs utilisées pour les très petites tables, pour toute table contenant plus de 500 lignes, avant SQL Server 2016, les statistiques étaient considérées comme "périmées" lorsque le nombre de modifications apportées à la colonne sur laquelle les statistiques étaient basées dépassait 20 % du nombre de lignes du tableau. Ainsi, pour une table de 1000 lignes, cela peut signifier 200 insertions, 200 mises à jour ou 200 suppressions. Il peut s'agir de modifications de 200 lignes ou de 5 lignes mises à jour 40 fois chacune. SQL Server nous offre même une fonction qui signale le nombre de modifications apportées. Vous devrez rechercher le numéro stats_id pour les statistiques qui vous intéressent, qui serait l'index_id si les statistiques appartiennent à un index. Le stats_id se trouve dans la vue appelée sys.stats. Dans ma table de newsales, j'utilise cette requête pour trouver que le stats_id pour l'index sur la colonne SubTotal est 3.

SELECT name, stats_id FROM sys.stats
WHERE object_id = object_id('newsales');

Ensuite, je peux utiliser cette valeur pour regarder le nombre de changements. Permettez-moi d'abord de mettre à jour certaines lignes :

UPDATE newsales
SET SubTotal = SubTotal * 0.9
WHERE SalesOrderID < 45200
(1541 lignes concernées)

SELECT * FROM sys.dm_db_stats_properties(object_id('newsales'), 3);  

En fait, 20 % est un GROS chiffre. Et pour de nombreuses tables, les requêtes peuvent bénéficier de statistiques mises à jour avec bien moins de 20 % des lignes mises à jour. À partir de 2008R2 SP1, SQL Server incluait un Traceflag que vous pouviez utiliser pour modifier le nombre de lignes en échelle mobile, comme indiqué dans le graphique suivant :

À partir de SQL Server 2016, ce nouvel algorithme avec l'échelle mobile est utilisé par défaut, tant que vous êtes au niveau de compatibilité 130 ou supérieur.

La plupart des recompilations automatiques des plans de requête sont dues à des changements dans les statistiques. Mais comme je l'ai mentionné ci-dessus, ce n'est pas la seule raison d'une recompilation. Mais comme c'est le plus courant, il peut être très utile de savoir quand et comment les statistiques sont mises à jour et assurez-vous que les statistiques de vos tables critiques sont mises à jour assez souvent pour vous assurer d'obtenir les meilleurs plans !

Analysez automatiquement les données de performances pour effectuer des diagnostics de serveur SQL afin de résoudre rapidement les problèmes et d'identifier les serveurs à l'origine de la dégradation des performances. Commencez à utiliser Spotlight Cloud dès aujourd'hui :