Obtenir des lignes insérées avec SqlBulkCopy

linq-to-sql sqlbulkcopy sql-server transactions

Question

Je commute une partie de mon code Linq sur Sql pour utiliser SqlBulkCopy, et le problème est que je dois effectuer deux insertions de plusieurs milliers de lignes dans deux tables.

Le service prend votre lot de 10 000 liens (importés à partir de sitemap, de constructeurs de liens en retour, etc.) et les découpe en flux RSS de X par flux pour l'agrégation. Le problème, c'est que j'ai déjà une table de 32 millions de lignes . Si je fais des insertions linq to sql, cela prend entre 5 et 10 minutes, selon le trafic du site, de charger 10 000 liens.

La structure est très basique.

Flux : Id bigint (PK), Titre varchar (1000), Description varchar (1000), Date-heure publiée, Date-heure agrégée nulle, ShortCode varchar (8) [ancien, plus inséré, mais utilisé pour les données héritées]

Articles : Id bigint (PK), FeedId bigint (FK), Titre varchar (1000), Description varchar (1000), Date de publication, ShortCode varchar (8) [ancien, plus inséré, mais utilisé pour les données existantes], ShortId bigint null [mis à jour après insertion pour correspondre à Id (utilisé dans le partitionnement)]

FutureItems : Id bigint (PK), FeedId bigint (FK), Titre varchar (1000), Description varchar (1000), Date de publication, ShortCode varchar (8) [ancien, plus inséré, mais utilisé pour les données existantes], ShortId bigint null [mis à jour après insertion pour correspondre à Id (utilisé dans le partitionnement)]

OldItems : Id bigint (PK), FeedId bigint (FK), Titre varchar (1000), Description varchar (1000), Date de publication, ShortCode varchar (8) [ancien, plus inséré, mais utilisé pour les données existantes], ShortId bigint null [mis à jour après insertion pour correspondre à Id (utilisé dans le partitionnement)]

Ainsi, si vous avez une taille de flux de 20, vous obtenez 500 insertions dans la table Feeds, puis 10 000 insérées dans la table Items, puis mettez à jour les exécutions pour définir le ShortId égal à l'ID. Une fois par nuit, un travail qui sépare les données dans les deux autres tables et déplace les éléments futurs dans la table des éléments est exécuté.

J'ai lu que SqlBulkCopy peut faire 20 millions de lignes en ce qui concerne les minutes, mais je ne trouve aucun bon exemple de le faire dans plusieurs tables avec une contrainte FK.

Notre serveur SQL est un "monstre" spécialement pour cette application. C'est SQL 2008 R2 Web, Windows 2008 R2 Entreprise, 12 Go de RAM, Dual 4 core Xeons @ 2.8ghz.

Notre serveur Web est un clone sans le service de base de données.

Le processeur tourne à environ 85% lors de l’insertion de liens et la base de données remplit la RAM.

Si SqlBulkCopy n'est pas bon, toute suggestion est la bienvenue, nous avons des clients payants qui se mettent en colère, et je ne suis pas un administrateur de base de données, mais un simple programmeur.

Réponse acceptée

SqlBulkCopy est en effet plus rapide que les inserts ordinaires. Mais est plus rapide car il peut transformer un travail qui exécute 1000 insertions par seconde en un travail qui effectue 10000 / sec. Si vous ne pouvez créer que 10 000 liens en 10 minutes, vous devez avoir des problèmes différents, quelque chose qu’une copie en bloc est peu susceptible de résoudre.

Vous devez d’abord déterminer pourquoi il faut si longtemps pour insérer 10000 liens. Une fois que vous avez compris que vous pouvez effectuer un appel déterminant si le transfert vers SqlBulkCopy est une solution. Je comprends que vous n’êtes pas un administrateur de base de données, mais je vais vous diriger vers un livre blanc intitulé "dbaish" pour résoudre les problèmes de performances de SQL Server: Attentes et files d’attente . Ce n’est pas une solution de recette simple, c’est une méthodologie qui vous apprendra à identifier les goulots d’étranglement liés aux performances dans SQL Server.

Et pour répondre à votre question: comment utiliser SqlBulkCopy quand il y a des contraintes? La question plus générique est de savoir comment faire des opérations d'insertion en masse lorsque des contraintes sont en place. Pour les volumes importants, on désactive les contraintes, effectue les téléchargements en bloc, puis active les contraintes. Pour des opérations en ligne simplifiées avec un temps d’immobilisation minimal (la base de données est fondamentalement "en panne" pour la période où les contraintes sont désactivées), on utilise une stratégie différente, à savoir pré-charger les données dans des tables de transfert, les valider opération de commutation de partition, voir Transfert efficace de données à l’aide de la commutation de partition .


Réponse populaire

Je pense que votre vrai problème en utilisant simplement une insertion en bloc est que vous avez besoin des identifiants de flux de l'insertion initiale pour les autres tables. Voici ce que je ferais. Utilisez une insertion en bloc pour insérer dans une table intermédiaire. Ensuite, utilisez un proc stocké pour effectuer les insertions dans la table réelle à l'aide d'un ensemble. Vous pouvez utiliser la clause output de l'insertion initiale dans la table de flux pour récupérer une variable de table avec les identificateurs de flux dont vous avez besoin pour les insertions dans les autres tables.



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi