7
votes

En parallèle des inserts massifs dans SQL Server de C # (pour une performance de meilleure heure)

Déclaration de problème: Comment faire paralléser des inserts dans SQL Server (2008)

J'effectue un calcul numérique massif pour la recherche scientifique dans C # Les travailleurs multithreads qui font essentiellement une chose: testez des milliers de configurations possibles (combinaisons matricielles) à travers une période de temps (en jours) et stockez les résultats dans une base de données SQL Server.

Si je stocke les résultats un à un en DB (~ 300.000 lignes par session informatique * 100 des sessions), l'une après l'autre, je finis à attendre des heures pour que le processus de stockage se termine.

La conception de la base de données est très simple:

  • combinaisons combinaisons

    CS_ID1, valeur A1, valeur B1, valeur C1
    CS_ID2, valeur A2, valeur B2, valeur C2
    .........

  • résultats par jour
    Cs_id1, jour1, résultat 1
    Cs_id1, jour2, résultat 2
    Cs_id1, jour3, résultat 3
    .........

    .........
    CS_ID2, jour1, résultat n
    Cs_id2, jour2, résultat n + 1
    CS_ID2, jour3, résultat N + 2

    Chaque "jeu de combinaisons" est testé contre les échantillons de jours et ses résultats par jour sont traités dans un seul filetage C #, où une requête LINQ / SQL est générée et envoyée à DB juste avant la fin du fil. À l'exception des séquences d'identifiant de combinaison, Il n'y a pas de relation logique entre les résultats . Ceci est très important: c'est pourquoi j'ai pensé à paralleraliser les trucs inserts comme équivalent à une vidage en vrac de blocs de résultat

    Un autre détail qui pourrait être important est que Il est possible de déterminer à l'avance de la quantité de lignes insérées dans la base de données (par bloc et au total) . Cela pourrait probablement aider à organiser des espaces de table, les diviser via des pages, pré-fixer des gammes d'identité afin de stocker des blocs simultanément, ou quelque chose comme ça (non, je ne suis pas "haut" ou quelque chose comme suit :-))

    Je souhaite la bienvenue à tout type de suggestions afin de rendre cet insertion de temps aussi court que possible.

    Veuillez prendre en compte que je suis un développeur C #, avec des connaissances de SQL Server très basiques et qui ne connaissent pas très bien les concepts de DBA techniques approfondis (j'ai vu que les modifications de verrouillage sont très nombreuses, qu'il existe également des capacités multithreadées et asynchrones, mais Je dois admettre que je suis perdu seul dans la forêt :-))


    J'ai 12 cœurs CPU disponibles et 24 béliers


    éditer: Tiebreaker
    Je souhaite la bienvenue à une suggestion intelligente sur le temps de surveillance de l'ensemble du processus: à partir de la création / extrémité C # Filets aux rapports détaillés SQL Server Insert (Que se passe-t-il quand, comment, comment, comment, et où). J'ai essayé de vous attacher à la journalisation, mais cela préjoint considérablement le temps de traitement, donc je recherche des solutions de contournement intelligentes qui sont assez transparentes avec un impact minimum. Idem pour la partie SQL Server: Je sais qu'il y a quelques journaux et surveillance SP disponibles. Je n'ai pas encore trouvé que ceux qui conviennent à ma situation.


4 commentaires

Un collègue a suggéré de sérialiser les résultats sur des fichiers binaires / textuels et de les jeter dans dB à l'aide d'un insert en vrac à partir de fichiers plats ... Vous n'êtes pas sûr d'être une solution sonore.


Je ne suis en aucun cas un dba, mais je me demanderais quelques choses ici: 1) Est-ce votre CPU qui le limite, ou un disque? 2) Le mécanisme de verrouillage de la DB permettra-t-il d'inserrer des inserts parallèles? Si elle est limitée de disque, et que le SGBD ne verrouille pas plusieurs processus, vous pouvez essayer de fractionnement des données à insérer sur plusieurs disques et de procédés de forcement pour les insérer.


Est-ce suffisant pour diviser les requêtes via des connexions séparées? Comment SQL Server réagit-il à cela, physique "physiquement"? Les inserts sont-ils vraiment écrits simultanément dans la DB, à différentes positions de rangée?


@syrion: Dès maintenant, je n'ai toujours aucune idée de si la CPU ou la HD limitent le processus. Je m'interroge simplement sur la meilleure chose à gérer cela, en général. En ce qui concerne mes connaissances, même si la DB autorise plusieurs processus, je ne sais pas s'il est possible pour deux (ou plus) processus d'écrire sur la même table simultanément, cette table serait-elle écartée sur différents HDS ou non.


7 Réponses :


5
votes

the insert en vrac pourrait aider ici.


0 commentaires


5
votes

Si vous utilisez une transaction distincte pour chaque insert, cela affecterait définitivement les performances, car le serveur DB devrait effectuer de manière atomique chaque insertion. Je n'ai jamais utilisé SQL Server, mais la plupart des variantes SQL ont un moyen de grouper plus d'un insertions dans une seule transaction, généralement avec quelque chose comme xxx

pour la syntaxe SQL Server voir:

http://msdn.microsoft.com/en-us/library /ms188929.aspx

http: // msdn.microsoft.com/en-us/library/ms190295.aspx

dans mon expérience Ensensiez des inserts comme celui-ci vous aide à définir avec les performances du serveur et, dans une certaine mesure, utilisation des ressources et du réseau. < / P>

Edit:

La plupart (tous?) Les serveurs DB décents utilisent une sorte de verrouillage par rangée, plutôt que des serrures par table. Vous devriez pouvoir avoir plusieurs transactions concurrentes, chacune avec plusieurs inserts, sans problème - c'est ce que les serveurs DB sont conçus pour. Vous pourriez certainement avoir chaque fil de travailleur exécuter ses propres transactions, parallèle les inserts de différents threads.

puisque vous utilisez apparemment un seul ordinateur pour les calculs et la base de données, de manière approfondie des transactions DB n'auraient aucune incidence sur la performance. Trop et cela pourrait même la rendre pire, puisque vous n'avez pas vraiment de latences de réseau pour réduire l'impact de. Tant que tous les cœurs de la CPU sont occupés, ce qui impliquerait probablement un certain nombre de travailleurs> = 12, vous devriez rechercher d'autres optimisations.

Si vos threads génèrent leur sortie en une fois après < / EM> Traitement (par exemple, si vous calculez une importante matrice et alors Dump in the Base de données) Je doute que vous gagnez tout en stockant le résultat dans un fichier, puis avec le DB la lire dans une Tableau.

Si, d'autre part, vos threads font leur pièce de sortie, vous pourriez bénéficier en stockant des parties de leur sortie en mémoire, puis insérez ces pièces dans la DB, effectuant plus d'une transactions par tour. Élever le nombre de threads de travailleurs dans ce cas pourraient vous permettre d'avoir une meilleure utilisation du processeur tandis que la base de données stocke les données, si la CPU est sous-utilisée.

stocker la sortie du travailleur dans Un fichier devrait être évité dans l'IMHO car il triple efficacement la charge sur le sous-système de disque. La seule raison pourriez-vous faire est que si vous n'avez vraiment pas la mémoire pour le stockage intermédiaire des résultats.


3 commentaires

Non, je n'ai certainement pas effectué une transaction par insertion (cela se retrouverait avec 300 000+ transactions :-)). Ma question concerne davantage la parallélisation des blocs des instructions d'insertion, plutôt que de les envoyer de bloc par bloc à la base de données.


Les envoyer en blocs peut améliorer définitivement les performances car vous ne faites pas un aller-retour sur SQL Server pour chaque insertion.


Merci pour votre édition utile. Mes discussions font en effet leur pièce de sortie. J'aurai un regard de près.



10
votes

300K inserts est une question de secondes, aux pires minutes, pas d'heures. Vous devez le faire mal. record du monde de l'ETL SSIS De retour en 2008 était à 2,36 tb / heure, 300k enregistrements sont rien .

Les règles de base du pouce sont les suivantes:

  • Batch commettre . C'est la chose la plus importante. N'insérez pas une ligne, puis insérez une ligne, puis insérez une rangée sur Nauseam, chaque insert Int sa propre transaction . Votre programme doit attendre que le journal (LDF) affleurait après chaque affirmation de son cas et sera lent. Très lent. Plotez plutôt une transaction, puis insérez un lot de lignes, puis commettez la transaction:

    pseudocode: xxx

    • Si possible, utilisez sqlbulkcopy

      La première option seule vous obtiendra au-dessus de 3 000 inserts par seconde (environ 2 minutes pour 300k). La deuxième option devrait vous mettre dans des dizaines de milliers par seconde portée. Si vous avez besoin de plus, il y a des astuces plus avancées:

      • Utilisez des tas au lieu de b-arbres (aucun index en cluster)
      • Désactiver les index secondaires
      • Affinitiser les clients aux nœuds numériques doux et appuyez sur des tables verrouillées par contact client, puis activez-les à l'aide de la commutation de partition à la fin. Ceci est pour vraiment haut de gamme, des millions de rangées par seconde.

        Je vous suggère de commencer avec les bases des bases: les engagements du lot.


4 commentaires

Merci pour votre Insight Remus, c'était très utile. Je ne me suis pas fait clairement sur la volumétrie: il s'agit de 300k + enregistrements par calcul, mais j'ai des centaines à peu de milliers de calculs tous les jours. De plus, notre DB est sur le point de croître vraiment énorme (ne peut pas exactement dire la taille pour l'instant, mais probablement quelques SCT). Un détail important est que j'utilise un cadre LINQ Orm (AgileFX), mais je suppose que je dois revenir à une solution faite à la main si je veux avoir des procédures de transaction personnelles ...


J'ai ajouté un "TRYBeaker" à la fin de mon post. Vous pouvez être d'une aide sur celle-ci aussi, concernant la surveillance de la DB


Pour surveiller le code C #, ajoutez des compteurs de performance à votre application: RUSANU.COM/2009/04/11/... . Pour surveiller la DB, essayez de suivre une procédure comme des attentes et des files d'attente: msdn.microsoft. COM / EN-US / Bibliothèque / CC966413.ASPX


Super. Je vais prendre un regard profond à cela. Beaucoup de merci!



1
votes

Peut-être que cela pourrait vous aider

J'ai un guide étape par étape sur la manière d'exécuter des procédures stockées parallèles dans SQL ici .

Vous pourriez être capable de combiner un insert en vrac avec celui-ci.


0 commentaires

2
votes

Vous pouvez essayer d'utiliser un parallèle pour pour faire les inserts. ..

... Mais j'essaierais un insert en vrac ou un titre de lot d'abord ...


0 commentaires

1
votes

C'est un problème intéressant. Tout d'abord, comment utilisez-vous les valeurs de la base de données? Participons-ils à des calculs suivants ou sont-ils simplement «Dump» pour stocker les résultats pour un traitement ultérieur? Aussi est votre application / processus fonctionnant 24 heures sur 24? de
Pourquoi suis-je demandé - si vous pouviez diviser les opérations "Résultats du magasin" et "résultats de processus", vous pouvez obtenir un débit supérieur en "blobbing" les données d'une session et les stocker comme une blob. Plus tard, dans le temps découvert, vous pouvez marcher et traiter et "étendre" ces blobs dans des tables par exemple à l'aide d'un travail ou d'un autre processus. En théorie, si cela irait bien, vous pouvez stocker ces blobs "stadification" dans des fichiers binaires, non directement dans la base de données, pour obtenir une vitesse d'écriture probablement maximale possible (limitée uniquement par le système de fichiers, le système d'exploitation et le matériel de disque sous-jacent).


2 commentaires

Eh bien, la chose simple à ce sujet est qu'il n'y a pas d'accès en écriture en lecture simultanée (pas encore, au moins). Je viens de jeter toutes les données de résultat directement dans la DB pour le traitement / l'exploitation des données ultérieures. NO 24H PROCESSUS: Les calculs vont tout comme les chercheurs le décident pendant la journée (et parfois, les serveurs font des travaux prévus de nuit).


Si je reçois votre idée, cela revient à reporter le processus de stockage afin de soulager temporairement la charge à partir des processeurs / base de données. N'y a-t-il pas pensé, pourrait être une alternative intéressante, pour un cas particulièrement utilise où l'analyste de la recherche Woudl sera correct pour attendre le jour après avoir obtenu les résultats et effectuer la "non-blâme" de nuit.