Mon entreprise utilise une application qui présente des problèmes de performances assez importants. Il y a un certain nombre de problèmes avec la base de données elle-même que je suis en train de résoudre, mais beaucoup de problèmes sont purement liés à l'application.
Dans mon enquête, j'ai découvert qu'il y avait des millions de requêtes frappant la base de données SQL Server qui interrogent des tables vides. Nous avons environ 300 tables vides et certaines de ces tables sont interrogées jusqu'à 100-200 fois par minute. Les tableaux n'ont rien à voir avec notre domaine d'activité et font essentiellement partie de l'application d'origine que le fournisseur n'a pas supprimée lorsqu'ils ont été engagés par mon entreprise pour produire une solution logicielle pour nous.
Outre le fait que nous soupçonnons que notre journal d'erreurs d'application est inondé d'erreurs liées à ce problème, le fournisseur nous assure qu'il n'y a aucun impact sur les performances ou la stabilité pour l'application ou le serveur de base de données. Le journal des erreurs est inondé dans la mesure où nous ne pouvons pas voir plus de 2 minutes d'erreurs pour effectuer des diagnostics.
Le coût réel de ces requêtes va évidemment être faible en termes de cycles CPU, etc. Mais quelqu'un peut-il suggérer quel serait l'effet sur SQL Server et l'application? Je soupçonne que les mécanismes réels d'envoi d'une demande, de confirmation, de traitement, de retour et d'accusé de réception de la demande auraient eux-mêmes un impact sur les performances.
Nous utilisons SQL Server 2008 R2, Oracle Weblogic 11g pour l'application.
@ Frisbee - Bref, j'ai créé une table contenant le texte de la requête qui a frappé les tables vides dans la base de données de l'application, puis je l'ai interrogé pour tous les noms de tables que je sais vides et j'ai obtenu une très longue liste. Le résultat le plus élevé a été de 2,7 millions d'exécutions sur 30 jours de disponibilité, sachant que l'application est généralement utilisée de 8h00 à 18h00, de sorte que ces chiffres sont plus concentrés sur les heures opérationnelles. Plusieurs tables, plusieurs requêtes, probablement certaines relavent via des jointures, d'autres non. Le résultat le plus élevé (2,7 millions à l'époque) était un simple choix dans une seule table vide avec une clause where, pas de jointure. Je m'attendrais à ce que des requêtes plus importantes avec des jointures aux tables vides puissent inclure des mises à jour des tables liées, mais je vais vérifier cela et mettre à jour cette question dès que possible.
Mise à jour: il y a 1000 requêtes avec un nombre d'exécutions compris entre 1043 et 4622614 (sur 2,5 mois). Je vais devoir creuser plus pour savoir d'où vient le plan mis en cache. C'est juste pour vous donner une idée de l'étendue des requêtes. La plupart sont raisonnablement complexes avec plus de 20 jointures.
@ srutzky- oui, je crois qu'il y a une colonne de date liée au moment où le plan a été compilé, ce qui serait intéressant, donc je vais vérifier cela. Je me demande si les limites de threads sont un facteur lorsque le serveur SQL se trouve sur un cluster VMware? Bientôt un Dell PE 730xD dédié, heureusement.
@Frisbee - Désolé pour la réponse tardive. Comme vous l'avez suggéré, j'ai exécuté une sélection * de la table vide 10 000 fois sur 24 threads à l'aide de SQLQueryStress (donc en fait 240 000 itérations) et j'ai immédiatement frappé 10 000 requêtes par lot. Ensuite, j'ai réduit à 1000 fois plus de 24 threads et atteint un peu moins de 4 000 demandes de lot / s. J'ai également essayé 10 000 itérations sur seulement 12 threads (donc 1 20000 itérations au total), ce qui a produit un maintien de 6 505 lots / s. L'effet sur le processeur était en fait notable, environ 5 à 10% de l'utilisation totale du processeur lors de chaque test. Les temps d'attente sur le réseau étaient négligeables (comme 3 ms avec le client sur mon poste de travail) mais l'impact du processeur était là, c'est certain, ce qui est assez concluant en ce qui me concerne. Il semble se résumer à l'utilisation du processeur et à un peu d'E / S de fichiers de base de données inutiles. Le nombre total d'exécutions / seconde s'élève à un peu moins de 3000, ce qui est plus qu'en production, mais je ne teste qu'une seule des dizaines de requêtes comme celle-ci. L'effet net de centaines de requêtes atteignant des tables vides à un taux compris entre 300 et 4000 fois par minute ne serait donc pas négligeable en ce qui concerne le temps CPU. Tous les tests effectués contre un PE 730xD inactif avec double baie flash et 256 Go de RAM, 12 cœurs modernes.
@ srutzky- bonne pensée. SQLQueryStress semble utiliser le regroupement de connexions par défaut, mais j'ai quand même regardé et j'ai constaté que oui, la case pour le regroupement de connexions est cochée. Mise à jour à suivre
@ srutzky- Le pool de connexions n'est apparemment pas activé sur l'application - ou s'il l'est, il ne fonctionne pas. J'ai fait une trace de profileur et j'ai constaté que les connexions ont EventSubClass "1 - Non groupé" pour les événements de connexion d'audit.
RE: Connection Pooling - Vérifié les weblogics et trouvé le pool de connexions activé. Ran plus de traces contre les signes en direct et trouvés de regroupement ne se produisant pas correctement / pas du tout:
Et voici à quoi cela ressemble lorsque j'exécute une seule requête sans jointure sur une table remplie; les exceptions indiquent "Une erreur liée au réseau ou spécifique à l'instance s'est produite lors de l'établissement d'une connexion à SQL Server. Le serveur n'a pas été trouvé ou n'était pas accessible. Vérifiez que le nom de l'instance est correct et que SQL Server est configuré pour autoriser les connexions à distance. (fournisseur: fournisseur de canaux nommés, erreur: 40 - Impossible d'ouvrir une connexion à SQL Server) "Notez le compteur de demandes par lots. Le ping du serveur pendant la génération des exceptions entraîne une réponse ping réussie.
Mise à jour - deux exécutions de test consécutives, même charge de travail (sélectionnez * fromEmptyTable), regroupement activé / non activé. Un peu plus d'utilisation du processeur et beaucoup d'échecs et ne dépasse jamais 500 requêtes par lot. Les tests montrent 10 000 lots / s et aucune défaillance avec le regroupement activé, et environ 400 lots / s, puis beaucoup d'échecs dus à la désactivation du regroupement. Je me demande si ces échecs sont liés à un manque de disponibilité de connexion?
@ srutzky- Sélectionnez Count (*) dans sys.dm_exec_connections;
Pooling activé: 37 de manière cohérente, même après l'arrêt du test de charge
Pooling désactivé: 11-37 selon que des exceptions se
produisent ou non sur SQLQueryStress, c'est-à-dire que lorsque ces creux apparaissent sur le
graphique Batch / sec, les exceptions se produisent sur SQLQueryStress et le
nombre de connexions tombe à 11, puis revient progressivement à 37 lorsque les lots commencent à culminer et que les exceptions ne se produisent pas. Très, très intéressant.
Le nombre maximal de connexions sur les deux instances de test / live est défini sur 0 par défaut.
Après avoir vérifié les journaux des applications et ne pas trouver de problèmes de connectivité, il ne reste que quelques minutes de journalisation disponibles en raison du grand nombre et de la taille des erreurs, à savoir: beaucoup d'erreurs de trace de pile. Un collègue du support des applications indique qu'un nombre important d'erreurs HTTP se produisent en raison de la connectivité. Il semblerait basé sur cela, que pour une raison quelconque l'application ne regroupe pas correctement les connexions et par conséquent, le serveur manque à plusieurs reprises de connexions. J'examinerai davantage les journaux d'application. Je me demande s'il existe un moyen de prouver que cela se produit dans la production du côté de SQL Server?
@ srutzky- Merci. Je vérifierai la configuration weblogic demain et mettrai à jour. Je pensais cependant aux 37 simples connexions - si SQLQueryStress fait 12 threads à 10 000 itérations = 120 000 instructions de sélection non regroupées, cela ne devrait-il pas signifier que chaque sélection crée une connexion distincte à l'instance SQL?
@ srutzky- Weblogics sont configurés pour regrouper les connexions, donc cela devrait fonctionner correctement. Le regroupement de connexions est configuré comme ceci, sur chacun des 4 blogues à charge équilibrée:
- Capacité initiale: 10
- Capacité maximale: 50
- Capacité minimum: 5
Lorsque j'augmente le nombre de threads exécutant la sélection à partir d'une requête de table vide, le nombre de connexions culmine autour de 47. Lorsque le pool de connexions est désactivé, je constate systématiquement une baisse du nombre maximal de demandes de lot / s (de 10 000 à environ 400). Ce qui se produira à chaque fois, c'est que les «exceptions» sur SQLQueryStress se produisent peu de temps après que les lots / s soient entrés dans un creux. C'est lié à la connectivité, mais je ne peux pas comprendre exactement pourquoi cela se produit. Lorsqu'aucun test n'est en cours, #connections descend à environ 12.
Avec la mise en commun des connexions désactivée, j'ai du mal à comprendre pourquoi les exceptions se produisent, mais peut-être qu'il s'agit d'une toute autre question stackExchange / question pour Adam Machanic?
@srutzky Je me demande alors pourquoi les exceptions se produisent sans regroupement activé, même si SQL Server ne manque pas de connexions?
SELECT COUNT(*) FROM sys.dm_exec_connections;
pour voir si la valeur est très différente entre le regroupement activé ou ne pas. Sur la base de ces erreurs, je pense qu'il y aurait beaucoup plus de connexions lorsque la mise en commun est désactivée.
Pooling=false
ou Max Pool Size
?