Préface
Il y a un système d'information que j'administre. Le système comprend les composants suivants :
1. Base de données MS SQL Server
2. Application serveur
3. Applications clientes
Ces systèmes d'information sont implantés sur plusieurs objets. Le système d'information est utilisé activement 24h/24 par 2 à 20 utilisateurs à la fois sur chaque objet. Par conséquent, vous ne pouvez pas effectuer l'entretien de routine en une seule fois. Donc, je dois «étaler» la défragmentation des index SQL Server tout au long de la journée, plutôt que de défragmenter tous les index fragmentés nécessaires d'un seul coup. Cela s'applique également aux autres opérations.
La propriété de mise à jour automatique des statistiques est définie dans les propriétés de la base de données. De plus, les statistiques sont mises à jour sur l'index défragmenté.
Problème
Il y a environ un an, j'ai rencontré le problème suivant :
De temps en temps, toutes les requêtes étaient lentes. Notamment, le temps de retard était aléatoire. C'est arrivé sur chaque objet un jour au hasard. De plus, lorsque j'ai commencé à analyser la fréquence des retards (à l'aide du profileur), j'ai découvert qu'ils se produisaient tous les jours à une heure aléatoire. Les utilisateurs n'y prêtent pas toujours attention, mais les considèrent comme le seul retard aléatoire, puis le système fonctionne à nouveau rapidement.
Résoudre le problème
J'ai passé en revue toutes les requêtes lentes. Le plus étrange était que toutes les requêtes s'exécutaient lentement à un moment aléatoire, même les plus simples, comme extraire le dernier enregistrement d'une table de plusieurs milliers de lignes.
De plus, j'ai effectué les étapes suivantes :
1. J'ai analysé les journaux MS SQL Server et Windows Server, mais je n'ai pas trouvé la cause des retards.
2. J'ai analysé les index (fragmentation, etc.), ajouté ceux qui manquaient et supprimé les inutilisés.
3. J'ai analysé les requêtes - certaines requêtes ont été améliorées.
4. J'ai analysé les tâches dans SQL Agent et je n'ai pas pu associer les tâches au problème de retard.
5. J'ai analysé les tâches dans le planificateur de tâches et je n'ai pas pu associer les tâches au problème de retard.
6. Profiler a montré les résultats, mais pas la cause des retards.
7. J'ai effectué une vérification des interblocages - aucun blocage de longue durée n'a été révélé.
En conséquence, j'ai passé plus de 3 mois sur la recherche infructueuse de la raison des requêtes occasionnelles lentes. Cependant, j'ai révélé un fait intéressant - au lieu de l'indicateur d'exécution Worker, l'indicateur d'attente écoulée a augmenté pour toutes les requêtes. Ce fait m'a donné l'idée que quelque chose ne va pas avec les disques. Je les ai vérifiés - tout allait bien.
Solution
À ma grande surprise, j'ai accidentellement révélé que lorsqu'une requête était exécutée lentement dans l'application, elle s'exécutait rapidement dans SSMS. Un article a aidé à résoudre le problème (au moins, il a suggéré l'idée).
Un paragraphe de l'article :
En pratique, l'option SET la plus importante est ARITHABORT, car la valeur par défaut de cette option est différente pour les applications et pour SQL Server Management Studio. Cela explique pourquoi vous pouvez détecter une requête lente dans votre application, puis obtenir une bonne vitesse en l'exécutant dans SSMS. L'application utilise un plan qui a été créé pour un ensemble de valeurs qui diffère des valeurs correctes réelles. Alors que si vous exécutez la requête dans SSMS, il est fort probable que le cache n'ait pas encore de plan d'exécution pour ARITHABORT ON, et donc SQL Server créera un plan pour vos valeurs actuelles.
La différence d'exécution était due au paramètre SET ARITHABORT. Pour toutes les requêtes exécutées dans SSMS, cette option est activée, et pour les requêtes de l'extérieur (des applications) - désactivée. Il ne peut pas être activé même par une simple requête pour les applications :
SET ARITHABORT ON;
Une idée folle a suivi - vider le cache procédural au moment du raccrochage.
Pour la vérification manuelle ultérieure, je dois écrire la déclaration suivante avant la requête dans SSMS :
SET ARITHABORT OFF;
Ainsi nous allons simuler le fonctionnement de l'application. Lorsque la requête était en cours d'exécution depuis longtemps, j'ai vidé le cache procédural. Et cela a toujours aidé. Avant d'effacer le cache procédural, la requête peut durer jusqu'à 20 à 30 secondes, puis 0 seconde.
Après cela, j'ai effectué une autre expérience :nettoyer l'intégralité du cache procédural pour l'ensemble de la base de données toutes les heures via SQL Agent :
--cleaning the cache by database id DBCC FLUSHPROCINDB (@db_id);
Après cela, toutes les requêtes ont été exécutées très rapidement (moins de 0,05 seconde). Il n'y a eu que quelques occurrences allant jusqu'à 5 à 10 secondes d'exécution, mais les utilisateurs n'ont remarqué aucun raccrochage. De plus, la mise à jour des statistiques n'améliorait pas les résultats, j'ai donc désactivé la mise à jour des statistiques.
Après quelques mois d'étude supplémentaires, j'ai découvert que des raccrochages occasionnels se produisent lorsque le cache consomme tout sur le serveur et qu'il ne reste plus d'espace libre ou qu'il y a de la mémoire libre, mais moins de 1 Go de RAM ou le service MS SQL Server occupe toute la RAM allouée (via le Gestionnaire des tâches). Mais le deuxième événement ne s'est produit que deux fois pendant toute l'étude.
Le fait est que littéralement tout est écrit dans le cache, alors que le cache n'est pas toujours libéré à temps. Le problème avec le cache a été résolu en utilisant le programme EmptyStandbyList.exe.
J'ai configuré cette application via le planificateur de tâches pour qu'elle s'exécute 1 fois par heure. Après tout le travail accompli, il n'y a plus de requêtes bloquées sur tous les objets depuis plus de six mois maintenant.
La seule chose qui reste floue, ce sont les rares cas où une requête raccroche pendant 5 à 10 secondes une fois par mois un jour et à une heure aléatoires. Il y a eu 4 cas de ce type et seulement sur deux objets pendant six mois lorsque le service MS SQL Server occupe toute la mémoire allouée pendant une courte période.
Fondamentalement, il n'est pas nécessaire de creuser plus profondément, car les utilisateurs ne remarquent aucun raccrochage et tout fonctionne bien, mais si quelqu'un a des idées, je serai reconnaissant de partager.
Cet article a été écrit pour aider ceux qui rencontrent de tels problèmes, car je n'ai pas trouvé de réponse complète sur Internet et j'ai passé beaucoup de temps à étudier le problème et à trouver la solution.
Voir aussi :
- Mise en œuvre de l'indicateur de performances SQL Server pour les requêtes, les procédures stockées et les déclencheurs
- Automatisation de la défragmentation d'index dans la base de données MS SQL Server
Outil utile :
dbForge Query Builder pour SQL Server - permet aux utilisateurs de créer rapidement et facilement des requêtes SQL complexes via une interface visuelle intuitive sans écriture manuelle de code.