Quelle est la taille de lot recommandée pour SqlBulkCopy?

87

Quelle est la taille de lot recommandée SqlBulkCopy? Je recherche une formule générale que je peux utiliser comme point de départ pour le réglage des performances.

Jonathan Allen
la source

Réponses:

97

J'ai un utilitaire d'importation installé sur le même serveur physique que mon instance SQL Server. À l'aide d'une personnalisation IDataReader, il analyse les fichiers plats et les insère dans une base de données à l'aide de SQLBulkCopy. Un fichier typique contient environ 6 millions de lignes qualifiées, avec en moyenne 5 colonnes de texte décimal et court, environ 30 octets par ligne.

Compte tenu de ce scénario, j'ai trouvé qu'une taille de lot de 5000 était le meilleur compromis de vitesse et de consommation de mémoire. J'ai commencé avec 500 et ai expérimenté avec plus grand. J'ai trouvé que 5000 était en moyenne 2,5 fois plus rapide que 500. L'insertion des 6 millions de lignes prend environ 30 secondes avec une taille de lot de 5000 et environ 80 secondes avec une taille de lot de 500.

10 000 n'était pas sensiblement plus rapide. Le passage à 50000 a amélioré la vitesse de quelques points de pourcentage, mais cela ne vaut pas la charge accrue sur le serveur. Au-dessus de 50 000 n'a montré aucune amélioration de la vitesse.

Ce n'est pas une formule, mais c'est un autre point de données que vous pouvez utiliser.

Alric
la source
3
Une chose à considérer est si la table est vide et a des index. Dans ces cas, vous souhaiterez peut-être tout télécharger en un seul lot comme indiqué ici: technet.microsoft.com/en-us/library/ms177445(v=sql.105).aspx "Si vous importez en masse des données dans une table vide avec des index et vous spécifiez la taille du lot, la table devient non vide après le premier lot. À partir du deuxième lot, les données sont entièrement consignées. Pour les tables indexées vides, envisagez d'effectuer l'importation en bloc en un seul lot. "
Sal
SqlBulkCopy transmet les données de la source (par exemple, DataTable) à Sql, alors quelle "charge accrue sur le serveur" a-t-il sur une grande taille de lot? (par exemple 50000)
BornToCode
29

C'est une question sur laquelle j'ai également passé un certain temps. Je cherche à optimiser l'importation de gros fichiers CSV (16+ Go, 65+ millions d'enregistrements et de plus en plus) dans une base de données SQL Server 2005 à l'aide d'une application console C # (.Net 2.0). Comme Jeremy l' a déjà souligné , vous devrez faire quelques ajustements pour votre situation particulière, mais je vous recommande d'avoir une taille de lot initiale de 500, et de tester les valeurs à la fois au-dessus et en dessous.

J'ai reçu la recommandation de tester des valeurs comprises entre 100 et 1000 pour la taille du lot de ce message du forum MSDN et j'étais sceptique. Mais lorsque j'ai testé des lots de 100 à 10 000, j'ai trouvé que 500 était la valeur optimale pour mon application. La valeur 500 pour SqlBulkCopy.BatchSizeest également recommandée ici .

Pour optimiser davantage votre opération SqlBulkCopy, consultez ce conseil MSDN ; Je trouve que l'utilisation de SqlBulkCopyOptions.TableLock aide à réduire le temps de chargement.

MagicAndi
la source
Je pense que l'exécution de la commande de copie en bloc sur le serveur lui-même serait probablement plus rapide.
Captain Kenpachi
16

Comme d'autres l'ont indiqué, cela dépend de votre environnement, en particulier du volume de lignes et de la latence du réseau.

Personnellement, je commencerais par définir la BatchSizepropriété sur 1000 lignes et voir comment cela fonctionne. Si cela fonctionne, je continue à doubler le nombre de lignes (par exemple à 2000, 4000, etc.) jusqu'à ce que j'obtienne un délai.

Sinon, si un timeout se produit à 1000, alors je diminue le nombre de lignes de moitié (par exemple 500) jusqu'à ce que cela fonctionne.

Dans chaque cas, je continue à doubler (en cas de succès) ou à réduire de moitié (en cas d'échec) la différence entre chacune des deux dernières tailles de lots tentées jusqu'à trouver un point idéal.

L'autre facteur à prendre en compte est le temps nécessaire pour copier un seul lot de lignes. Des délais d'expiration se produiront si le lot de lignes copiées dépasse la BulkCopyTimeoutpropriété qui par défaut est de 30 secondes. Vous pouvez essayer de doubler la BulkCopyTimeoutpropriété à 60 secondes. Cela permet une plus longue période de temps pour un plus grand ensemble de lignes de lots à copier. Par exemple, un lot de 50000 lignes peut prendre environ 40 secondes, dépassant juste la limite de temps de 30 secondes, donc le dépasser jusqu'à 60 secondes peut améliorer les performances.

Rayon
la source
4

Tout dépend de votre implémentation.

À quel type de vitesse pouvez-vous vous attendre sur votre réseau? L'utilisez-vous dans Forms ou ASP.Net? Avez-vous besoin d'alerter l'utilisateur des progrès? Quelle est la taille du travail total?

D'après mon expérience, l'exécution d'une copie en bloc sans taille de lot spécifiée entraînera des problèmes de délai d'expiration. J'aime commencer avec quelque chose comme 1000 disques et faire quelques ajustements à partir de là.

Jérémie
la source
Vitesse: Varie, WebForms: Oui, ASP.NET: Oui, Tables larges: Oui, Tables étroites, Oui. Des milliers de lignes: oui. Des millions de lignes: oui. Si vous pouvez penser à un scénario, je le fais probablement.
Jonathan Allen
1
Je dois donc m'en tenir à ma réponse précédente. Je ne pense pas qu'il y ait une solution miracle.
Jeremy
-1

j'avais essayé plusieurs tailles, dans mon cas, 5000 était bien

Un Mustapha
la source