Comment réduire la croissance du journal des transactions pour les mises à jour batched nvarchar (max)

StackOverflow https://stackoverflow.com/questions/2014670

Question

Notre application a besoin d'ajouter de grandes quantités de texte à base de données SQL Server 2005 (jusqu'à 1 Go pour un seul enregistrement). Pour des raisons de performance, cela se fait en morceaux, en faisant un appel de procédure stockée pour chaque morceau (par exemple, usp_AddChunk). usp_AddChunk n'a pas de transactions explicites.

Ce que je vois est que la réduction de la taille des blocs de 100MB aux résultats de 10MB dans les journaux de transactions massivement plus importants. On m'a dit que c'est parce que chaque fois usp_AddChunk est appelé, une transaction « implicite » (mon terme) enregistrera tout le texte existant. Donc, pour un enregistrement 150MB:

taille de bloc de 100 Mo: 100 (0 octets enregistrés) + 50 (100 Mo connectés) = 100 Mo connectés

sera inférieur à

10 MB taille de bloc: 10 (0 octets enregistrés) + 10 (10 MB connecté) + 10 (20 Mo connecté) ... + 10 (140 MB connectés) = 1050 MB connecté

Je pensais que l'ouverture d'une transaction dans mon code C # (avant d'ajouter le premier morceau, et commets après le dernier morceau), cette opération « implicite » ne se produirait pas, et je ne pouvais éviter les énormes fichiers journaux. Mais mes tests montrent le journal des transactions de plus en plus 5x plus en utilisant la transaction ADO.NET.

Je ne vais pas poster le code, mais voici quelques détails:

  1. J'appelle SqlConnection.BeginTransaction ()
  2. J'utilise un autre SqlCommand pour chaque morceau
  3. I assigner le SqlTransaction à partir de (1) à chaque SqlCommand
  4. Je ferme généralement la connexion après chaque exécution SqlCommand, mais je l'ai aussi essayé de ne pas fermer la connexion avec les mêmes résultats

Quelle est la faille dans ce système? Tenez-moi au courant si vous avez besoin de plus d'informations. Merci!

Remarque: en utilisant un modèle de récupération simple ou en vrac est connecté pas une option

Était-ce utile?

La solution

Si par 'morceaux' que vous voulez dire quelque chose comme:

UPDATE table
SET blob = blob + @chunk
WHERE key = @key;

Ensuite, vous avez raison que l'opération est entièrement connecté. Vous devez suivre la directives d'utilisation de blob et l'utilisation les méthodes .write pour les mises à jour chuncked:

UPDATE table
SET blob.Write(@chunk, NULL, NULL)
WHERE key = @key;

consignera au minimum la mise à jour (si possible, voir opérations qui peuvent être journalisée ):

  

L'instruction UPDATE est enregistrée complètement;   cependant, les mises à jour partielles à grande   les types de données en utilisant la valeur .WRITE   clause sont journalisée.

Non seulement que cela est peu connecté, mais parce que la mise à jour est une écriture explicite à la fin de blob, le moteur ne saura que vous ne mis à jour une partie de blob et ne log que . Lorsque vous mettez à jour avec le moteur SET blob=blob+@chunk de te verra que le blob entier a reçu une nouvelle valeur et ne détecte pas le fait que vous avez vraiment changé le blob en ajoutant de nouvelles données, de sorte que le il vous connecterez l'ensemble blob (plusieurs fois, comme vous avez déjà découvert).

BTW, vous devez utiliser des morceaux de taille multiple de 8040:

  

Pour des performances optimales, nous vous recommandons   que les données soient insérées ou mises à jour dans   bloc de taille qui sont des multiples de 8040   octets.

Autres conseils

Qu'est-ce que vous avez à faire est entourer chaque « morceau » ou groupe de morceaux avec sa propre transaction et commit après chaque groupe. Autour de la chose entière avec votre propre transaction ADO fait essentiellement la même chose que la transaction implicite ne, de sorte que ne va pas aider. Vous devez vous engager dans de plus petits morceaux pour garder le journal plus petit.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top