Déclaration de problème: Comment faire paralléser des inserts dans SQL Server (2008) forte> p>
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.
La conception de la base de données est très simple: p>
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 forts>. Ceci est très important: c'est pourquoi j'ai pensé à paralleraliser les trucs inserts comme Je souhaite la bienvenue à tout type de suggestions afin de rendre cet insertion de temps aussi court que possible. éditer: em>
Tiebreaker fort>
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.
p>
CS_ID1, valeur A1, valeur B1, valeur C1
CS_ID2, valeur A2, valeur B2, valeur C2
......... fort>
Li>
Cs_id1, jour1, résultat 1
Cs_id1, jour2, résultat 2
Cs_id1, jour3, résultat 3
......... fort>
......... strong>
CS_ID2, jour1, résultat n
Cs_id2, jour2, résultat n + 1
CS_ID2, jour3, résultat N + 2
LI>
ul>
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 em> forte> (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 :-)) p>
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 P>
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. Em> p>
7 Réponses :
Voici un article sur le fait de faire une insertion en vrac à l'aide de C #: http://blogs.msdn.com/b/nikhilsi/archive/2008/06/11/bulk-insert-into-sql-from-c-app.aspx p>
Des pensées supplémentaires sur l'insert en vrac avec C # sont dans une question de dépassement de pile:
Quel est le meilleur moyen d'inserts de base de données en vrac de C #? < / a> p>
J'espère que cela aide. P>
Merci, cela semble intéressant en effet. Je suis toujours curieux de savoir comment cela diffère-t-il techniquement des transactions régulières et pourquoi est-ce plus rapide, je vais donc creuser cela un peu. La partie délicate est que j'utilise une orme à base de Linq (AgileFX) et je ne sais pas si cela est réalisable "tel quel".
D'accord. Je n'ai pas beaucoup joué avec Linq (encore) Je ne suis donc pas sûr que c'est compatible. J'espère que c'est.
La différence entre les inserts normaux et en vrac est la méthode utilisée pour mettre à jour B-Tree. Inserts normaux Suivez l'approche classique "Top Down / Split", les inserts en vrac construisent l'arbre des feuilles.
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 pour la syntaxe SQL Server voir: P > http://msdn.microsoft.com/en-us/library /ms188929.aspx P> http: // msdn.microsoft.com/en-us/library/ms190295.aspx P> 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: P> 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. P> 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. P> 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 em> 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. P> 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 em> la CPU est sous-utilisée. P> 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. P> P>
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.
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 em>. Les règles de base du pouce sont les suivantes: p> pseudocode: p> 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: p> Je vous suggère de commencer avec les bases des bases: les engagements du lot. p> p>
sqlbulkcopy Code>
li>
ul>
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!
Peut-être que cela pourrait vous aider p>
J'ai un guide étape par étape sur la manière d'exécuter des procédures stockées parallèles dans SQL ici . P>
Vous pourriez être capable de combiner un insert en vrac avec celui-ci. P>
Vous pouvez essayer d'utiliser un parallèle pour pour faire les inserts. .. p>
... Mais j'essaierais un insert en vrac ou un titre de lot d'abord ... P>
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). p>
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.
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.