Quel est le moyen le plus efficace de mettre à jour des milliers d'loggings

Nous avons une application C # qui parsing datatables des files text. Nous devons ensuite mettre à jour les loggings dans notre database sql en fonction des informations contenues dans les files text. Quel est le moyen le plus efficace de transmettre datatables de l'application au server SQL?

Nous utilisons actuellement une string délimitée, puis une boucle dans la string dans une procédure stockée pour mettre à jour les loggings. Je teste également en utilisant TVP (paramètre de table évalué). Y a-t-il d'autres options?

Nos files contiennent des milliers d'loggings et nous aimerions une solution qui prend le less de time.

Merci de ne pas utiliser de DataTable car cela ne ferait que gaspiller du CPU et de la memory sans aucun bénéfice (autre que la familiarité). J'ai détaillé une approche très rapide et flexible dans ma réponse aux questions suivantes, qui est très similaire à celle-ci:

Comment puis-je insert 10 millions d'loggings dans les plus brefs timeouts?

L'exemple montré dans cette réponse est pour INSERT seulement, mais il peut facilement être adapté pour inclure UPDATE. En outre, il télécharge toutes les lignes dans un seul plan, mais cela peut également être facilement adapté pour définir un countur pour X nombre d'loggings et pour quitter la méthode IEnumerable après que plusieurs loggings ont été transmis, puis fermez le file une fois qu'il y a plus d'loggings. Cela nécessiterait de stocker le pointeur de file (c'est-à-dire le stream) dans une variable statique pour continuer à passer à la méthode IEnumerable afin qu'il puisse être avancé et ramassé à la position la plus récente la prochaine fois. J'ai un exemple de travail de cette méthode montré dans la réponse suivante, bien qu'il utilisait un SqlDataReader comme input, mais la technique est la même et nécessite très peu de modification:

Comment split une grande table contenant 100 millions de données en plusieurs tables?

Et pour un peu de perspective, 50k disques n'est même pas proche de "énorme". J'ai téléchargé / fusionné / synchronisé des données en utilisant la méthode que je montre ici sur 4 millions de files de lignes et qui a frappé plusieurs tables avec 10 millions (ou plus) de lignes.


Choses à ne pas faire:

  • Utiliser un DataTable : comme je l'ai dit, si vous le remplissez simplement dans le but d'utiliser avec un TVP, c'est un gaspillage de CPU, de memory et de time.
  • Faire 1 mise à jour à la fois en parallèle (comme suggéré dans un commentaire sur la question): c'est juste fou. Les moteurs de bases de données relationnelles sont fortement adaptés pour fonctionner de manière plus efficace avec des sets, et non des opérations singleton. Il n'y a aucun moyen que 50k inserts seront plus efficaces que même 500 inserts de 100 lignes chacun. Le faire individuellement garantit juste plus de contention sur la table, même si seulement des verrous de ligne (c'est 100k lock + unlock operations). Cela pourrait être plus rapide qu'une seule transaction de ligne de 50k qui se transforme en un verrou de table (comme Aaron l'a mentionné), mais c'est pourquoi vous le faites en plus petits lots, tant que small ne signifie pas 1 row;).
  • Définissez arbitrairement la taille du lot. Rester en dessous de 5000 lignes est bon pour aider à réduire les chances d'escalade de locking, mais ne choisissez pas seulement 200. Expérimentez avec plusieurs tailles de lots (100, 200, 500, 700, 1000) et essayez-les plusieurs fois. Vous verrez ce qui est le mieux pour votre système. Assurez-vous simplement que la taille du lot est configurable via le file app.config ou d'autres moyens (table dans la database, paramètre de registre, etc.) afin de pouvoir le modifier sans avoir à redéployer le code.
  • SSIS (puissant, mais très encombrant et pas amusant à déboguer)

Ce qui fonctionne, mais pas aussi flexible qu'un TVP correctement fait (c'est-à-dire en passant une méthode qui renvoie IEnumerable<SqlDataRecord> ). Ce sont ok, mais pourquoi vider les loggings dans une table temporaire juste pour avoir à les parsingr dans la destination quand vous pouvez le faire tout en ligne?

  • BCP / OPENROWSET (VRAC …) / INSERT EN VRAC
  • SqlBulkCopy de .NET

La meilleure façon de le faire à mon avis est de créer une table temporaire puis d'utiliser SqlBulkCopy pour l'insert dans cette table temporaire ( https://msdn.microsoft.com/fr-fr/library/system.data.sqlclient.sqlbulkcopy%28v = vs.110% 29.aspx ), puis simplement mettre à jour la table en fonction de la table temporaire.

Basé sur mes tests (en utilisant Dapper et aussi LINQ), la mise à jour en masse ou avec des lots prend beaucoup plus de time que de créer une table temporaire et d'envoyer une command au server pour mettre à jour datatables basées sur la table temporaire. Le process est plus rapide car SqlBulkCopy remplit datatables en mode natif de manière rapide, et le rest est effectué du côté du server SQL qui passe par less d'étapes de calcul, et datatables à ce stade résident à la fin du server.