L'insertion augmente les performances sous charge: pourquoi?

19

J'ai un morceau de code qui effectue des insertions dans des tables hautement dénormalisées. Les tableaux ont un nombre de colonnes allant de ~ 100 à 300+. Il s'agit de SQL Server 2008 R2, exécuté sur Windows Server 2008.

Chaque insert consiste à insérer dans un certain nombre de tables sous la même transaction. Certains encarts sont groupés par NHibernate, mais certains ne peuvent pas l'être, mais ils sont néanmoins tous soumis à la même transaction.

Lorsque j'effectue des insertions 500 fois par exemple en appelant à plusieurs reprises un morceau de code qui effectue l'insertion, j'obtiens en moyenne ~ 360 ms.

Le plus étrange est que lorsque j'exécute le code de test simultanément à l'aide de 4 processus (le même exe exécuté à partir de 4 invites de commande différentes sous Windows Server 2008), les performances d'insertion par appel s'améliorent beaucoup. Je vois des rafales qui vont aussi vite que 90 ms (presque X4 plus vite). Je mesure le temps d'insertion du code.

Étant donné que les 4 processus ne se connaissent pas, je suppose que cela a quelque chose à voir avec SQL Server, mais je ne sais absolument pas pourquoi. J'aimerais savoir pourquoi cela se produit et s'il existe une configuration qui me permettrait d'obtenir les mêmes performances lorsque les insertions ne sont pas si fréquentes.

Les suggestions concernant les méthodes de surveillance de SQL Server pour comprendre ce qui se passe au niveau de la base de données sont également les bienvenues.

mahonya
la source

Réponses:

15

Une raison possible est que quatre processus simultanés génèrent un modèle plus favorable de vidages de journal, ce qui signifie généralement que chaque vidage de journal écrit plus de données que dans le cas d'un seul processus d'exécution.

Pour déterminer si le débit du journal des transactions / la taille de vidage est un facteur, surveillez:

Recherchez les limites internes atteintes. Dans SQL Server 2008 R2, il peut y avoir un maximum de 32 E / S de vidage de journal (asynchrones) par base de données sur les versions 64 bits (seulement 8 sur 32 bits). Il y a également une limite de taille totale sur les E / S en attente de 3840 Ko.

Plus d'informations et lectures complémentaires:

Paul White dit GoFundMonica
la source
12

Tout ce que @PaulWhite dit, plus ...

Si vous avez des clés étrangères en place, chaque insert nécessitera une vérification à faire sur chaque table référencée. Il me semble que vous êtes, car vous n'obtenez que 360 ​​ms, ce qui me semble lent.

Quoi qu'il en soit, la vérification de ces tables est extrêmement utile en ayant déjà ces données dans la RAM, plutôt que de les charger sur le disque.

Il me semble que le chargement des données dans la RAM est une partie importante de votre exécution, et qu'il ne doit se produire qu'une seule fois.

Cela peut également être une mise en cache de plan efficace et que vos requêtes doivent être compilées la première fois, les appels suivants pouvant éviter cette phase.

Rob Farley
la source
Merci Rob. Mon problème de performances est lié au nombre élevé de tables utilisées lors d'une insertion. Il n'y a pas de clés étrangères, je les ai supprimées pour des raisons de performances et mes exigences de modèle et de domaine me permettent de le faire. Je ne charge pas de données dans la RAM et mes insertions sont façonnées dynamiquement par les demandes entrantes, qui changent tout le temps. J'utilise essentiellement un schéma étoile / flocon de neige (ish) pour OLTP et j'essaie de m'en tirer avec les meilleures performances possibles.
mahonya
2
@mahonya, même si vous ne chargez pas explicitement les données dans la RAM, SQL Server doit d'abord lire l'index et les pages de données nécessaires dans le cache de tampon avant d'effectuer l'opération d'insertion. Les threads d'insertion simultanés peuvent avoir pour effet de réchauffer le cache de telle sorte qu'un thread entraîne la surcharge de lecture et que l'autre accède aux données du cache.
Dan Guzman
Merci @DanGuzman - et oui, mahonya, il y a de fortes chances que votre cache soit bien réchauffé. Je vérifierais vos attentes pour voir si c'est des E / S physiques qui causent votre goulot d'étranglement.
Rob Farley
Merci @DanGuzman D'accord, l'accélération du cache d'index db est quelque chose que j'ai l'habitude de voir dans les postgres, j'ai probablement mal compris l'entrée de Rob.
mahonya
-3

certains serveurs / cpus / os se souviennent des modèles. comme cache.

Puisque vous faites la même chose 4 fois, je suis sûr qu'il existe des moyens de réduire les coins, ce que je suppose, c'est que la première façon de le faire, il le considère comme un long processus (exemple 1) mais dans le second est voit le code réutilisé et l'exécute comme cache (exemple2) ou il pourrait être le premier processus est trop grand pour tout contenir dans le (exemple de ram3).

exemple1: 0111110000110111110000111011111000011110111110000

exemple2: 0111110000 | 11 | 0111110000 | 111 | 0111110000 | 1111 | 0111110000

exemple3: 0111110000011111000001111100000111110000 exemple3: boucle: 0111110000

Je sais que le serveur Ubuntu le fait avec des requêtes répétées sur mysql. Je peux les enregistrer dans le cache, bien que la seule différence de temps soit de 10 à 40 mm, mais cela s'additionne. Quand j'étais à l'école, il y avait des cours qui montraient qu'il fallait que les programmes (perl / php) utilisent ce cache pour être plus rapides.

Mais, cela peut dépendre du programme, de la langue, de la compilation et de la façon dont il a été programmé.

Bryku
la source