La parallélisation massive insère dans SQL Server à partir de C# (pour une meilleure performance en temps)
Énoncé du problème : Comment paralléliser insère dans SQL Server (2008)
Je suis l'exécution massive de calcul numérique pour la recherche scientifique en C# multithread travailleurs qui, fondamentalement, ne faire qu'une chose : Tester des milliers de configurations possibles (combinaisons de matrice) à travers une période de temps (en jours) et de stocker les résultats dans une Base de données SQL Server.
Si je stocker les résultats un par un en DB (~300.000 lignes par session informatique * 100 de séances), l'un après l'autre, j'ai attendu pendant des heures pour la procédure de sauvegarde à la fin.
La conception de base de données est très simple :
- Combinaison Des Ensembles De
CS_ID1, la Valeur de A1, la Valeur de B1, la Valeur C1
CS_ID2, la Valeur de A2, Valeur B2, la Valeur de C2
......... - Résultats par Jour
CS_ID1, Day1,Résultat 1
CS_ID1, Day2,Résultat 2
CS_ID1, Jour3,Résultat: 3
..................
CS_ID2, Day1, Résultat N
CS_ID2, Day2, Résultat N+1
CS_ID2, Jour3, Résultat N+2
Chaque "Combinaison" est testé par rapport à l'échantillon jours et son par-résultats de la journée sont traitées dans un seul C# thread, où une LINQ/requête SQL est généré et envoyé à DB, juste avant la fin du thread. À l'exception de combinaison des Id de séquences, il n'y a PAS de relation logique entre les Résultats. Ceci est très important : C'est pourquoi j'ai pensé à la parallélisation de l'insérer des trucs comme essentiellement, il s'élève à un bulk dump de blocs de résultats
Un autre détail qui peut être important, c'est que il est possible de déterminer à l'avance combien de lignes sont insérées dans la Base de données (par bloc et au total). C'est probablement ce qui pourrait aider à organiser des espaces de tables, de les diviser par le biais de pages, pré-fix id plages afin de stocker les blocs simultanément, ou quelque chose comme ça (Non, je ne suis pas "élevé" ou quelque chose 🙂 )
Je souhaite la bienvenue à tout type de suggestions dans le but de rendre cette insérer un temps aussi court que possible.
Veuillez prendre en compte que je suis un développeur C#, avec de très de base SQL Server connaissance et pas très familier avec une profonde technique DBA concepts (j'ai vu que le Verrouillage des réglages sont TRÈS nombreux, qu'il y a multithread et asynchrone capacités, trop, mais je dois avouer que je suis perdu, seul, dans la forêt 🙂 )
J'Ai 12 Cœurs de PROCESSEUR disponibles, et 24Go de RAM
EDIT:
De bris d'égalité
Je souhaite la bienvenue à tout habile suggestion sur le temps de surveillance pour l'ensemble du processus : à Partir de C# threads début/fin détaillées sur SQl server insérer des états (Ce qui arrive quand, comment et où).
J'ai essayé de journalisation avec NLog mais de manière drastique les préjugés du temps de traitement je suis à la recherche pour certains smart solutions qui sont vraiment en douceur avec un minimum d'impact. De même pour le serveur SQL partie : je sais qu'il y a un couple de Journaux et de surveillance de la SP est disponible. Je n'ai pas encore lesquels fonction de ma situation.
- Un collègue a suggéré de sérialiser les résultats sur binary/les fichiers texte et les jeter tous en DB à l'aide de l'instruction Bulk Insert à partir de fichiers plats... ce n'est Pas sûr que le fait d'être une bonne solution.
- Je ne suis pas un DBA, mais je me demande deux choses ici: 1) oui, c'est ton CPU qui est de la limiter ou de disque? 2) le mécanisme de verrouillage de la DB en fait en parallèle des inserts? Si c'est le disque limité, et le SGBD n'a pas de lock-out de plusieurs processus, vous pouvez essayer de fractionnement de l'insertion de données sur plusieurs disques et bifurquer processus pour les insérer.
- Est-ce suffisant pour diviser les requêtes via des connexions distinctes ? Comment SQL Server réagir à cela, "physiquement" ? Sont des éléments vraiment écrit simultanément dans la DB, à différentes positions de ligne ?
- A partir de maintenant, je n'ai toujours aucune idée de savoir si le PROCESSEUR ou de la HD est de limiter le processus. Je me demande quelle est la meilleure chose à gérer cela, en général. Aussi loin que mes connaissances en va, même si le DB autorise de multiples processus, je ne sais pas si c'est possible pour deux (ou plus) à écrire sur la même table en même temps, est-ce que le tableau soit divisé entre différents HDs ou pas.
Vous devez vous connecter pour publier un commentaire.
Si vous utilisez une transaction distincte pour chaque insertion, qui aurait certainement affecter les performances, comme le serveur de base de données devra atomiquement effectuer chaque insertion. Je n'ai jamais utilisé de SQL server, mais la plupart SQL variantes ont une façon de groupe de plus que l'on insère dans une transaction unique, généralement avec quelque chose comme
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, le regroupement des inserts comme cela aide vraiment avec les performances du serveur et, dans une certaine mesure, des ressources et de l'utilisation du réseau.
EDIT:
La plupart (tous?) décent DB serveurs utilisent un certain type de par le verrouillage de ligne, plutôt que par des verrous de table. Vous devriez être en mesure d'avoir plusieurs transactions simultanées, chacune avec plusieurs inserts, aucun problème - c'est ce que DB serveurs sont conçus pour. Vous pourriez certainement avoir chaque thread de mener ses propres opérations, ainsi parallélisant les inserts de différents threads.
Puisque vous êtes apparemment en utilisant un seul ordinateur pour les calculs et la DB, largement parallélisation de transactions DB ne serait pas affecter les performances de trop et il pourrait même empirer, puisque vous n'avez pas vraiment tout les latences réseau afin de réduire l'impact de. Tant que tous les cœurs du PROCESSEUR sont occupés, ce qui pourrait impliquer un certain nombre de travailleurs >= 12, vous devriez être à la recherche à d'autres optimisations.
Si votre fils générer leur sortie dans un aller après de traitement (par exemple, si vous calculer une matrice de grande taille et puis vidage de la base de données) je doute que vous n'obtiendrez rien en stockant le résultat dans un fichier puis d'avoir la DB lire dans une table.
Si, d'autre part, votre fils ne leur sortie morceau par morceau, vous pouvez bénéficier de stocker des parties de leur sortie dans la mémoire, l'insertion de ces parties dans la DB, qui occupent plus d'un transactions par tour. Augmenter le nombre de threads de travail dans ce cas pourriez vous permettent d'avoir une meilleure utilisation CPU alors que la DB est de stocker les données, si le CPU est sous-exploité.
Stocker le travailleur de sortie dans un fichier devrait AMHA être évitée, car cela efficacement les triplets de la charge sur le sous-système de disque. La seule raison que vous voulez faire si vous n'avez pas vraiment la mémoire pour le stockage intermédiaire des résultats.
300k inserts est une question de secondes, au pire quelques minutes, pas heures. Vous devez être fais mal. Le ETL SSIS record du monde en 2008, a été à 2.36 to/h, 300k dossiers est rien.
Les règles de base du pouce sont:
Pseudocode:
SqlBulkCopy
La première option, vous obtiendrez au-dessus de 3000 insère par seconde (~2 minutes pour 300k). Deuxième option devrait vous amener des dizaines de milliers par seconde gamme. Si vous avez besoin de plus, il y a de plus avancé astuces:
Je vous suggère de commencer avec les bases, les principes de base: validation du lot.
La
BULK INSERT
peut aider à ici.Voici un article sur le fait de faire l'insertion en bloc à l'aide de C#:
http://blogs.msdn.com/b/nikhilsi/archive/2008/06/11/bulk-insert-into-sql-from-c-app.aspx
Réflexions supplémentaires sur bulk insert avec C# sont dans un Débordement de Pile question:
Quelle est la meilleure façon d'en bloc de la base de données des inserts à partir de c#?
Espère que cette aide.
Vous pouvez essayer d'utiliser un Parallèle Pour faire les inserts...
... mais je voudrais essayer d'INSERTION en bloc ou Lot de fabrication validé la première...
C'est un problème intéressant. Tout d'abord, comment utilisez-vous les valeurs dans la base de données? Ils participent dans la suite des calculs ou de la base de données est juste "dump" pour stocker les résultats pour un traitement ultérieur? Aussi est vous application/un processus qui fonctionne 24 heures par jour?
Pourquoi suis-je demander - si vous pourriez diviser le "magasin de résultats" et "résultats", vous pourriez atteindre un débit plus élevé en "blobbing" les données d'une session et de les stocker comme un blob. Plus tard, en hors-coup d'oeil de temps, on pouvait marcher et de processus et de "développer" ces derniers dans les tableaux par exemple à l'aide de travail ou d'un autre processus. En théorie, si ce serait OK, vous pouvez stocker ces "mise en scène" des gouttes dans les fichiers binaires, et non pas directement dans la base de données, pour atteindre probablement le maximum possible de la vitesse d'écriture (limité uniquement par le système de fichiers de l'OS sous-jacent et disque de matériel).
Peut-être cela peut vous aider à
J'ai un guide étape par étape sur la façon d'exécuter en parallèle des procédures stockées dans SQL ici.
Vous pourriez être en mesure de combiner bulk insert avec celui-ci.