web-dev-qa-db-fra.com

Quel est le moyen le plus rapide d'insérer un grand nombre de lignes?

J'ai une base de données où je charge des fichiers dans une table intermédiaire, à partir de cette table intermédiaire, j'ai 1-2 jointures pour résoudre certaines clés étrangères, puis j'insère ces lignes dans la table finale (qui a une partition par mois). J'ai environ 3,4 milliards de lignes pour trois mois de données.

Quel est le moyen le plus rapide d'obtenir ces lignes de la mise en scène dans la table finale? Tâche de flux de données SSIS (qui utilise une vue comme source et a un chargement rapide actif) ou une commande Insérer INTO SELECT ....? J'ai essayé la tâche de flux de données et je peux obtenir environ 1 milliard de lignes en environ 5 heures (8 cœurs/192 Go RAM sur le serveur), ce qui me semble très lent.

28
nojetlag

Une approche commune:

  1. Désactiver/supprimer les index/contraintes sur la table cible.
  2. INSERT dbo.[Target] WITH (TABLOCKX) SELECT ...
  3. Avec JNK, bien sûr, vous pouvez effectuer les opérations ci-dessus par lots de lignes n, ce qui peut réduire la pression sur le journal des transactions et, bien sûr, signifie que si un lot échoue, vous n'avez qu'à commencer à partir de ce lot. J'ai blogué à ce sujet (alors qu'en référence aux suppressions, les mêmes concepts de base s'appliquent) ici: http://www.sqlperformance.com/2013/03/io-subsystem/chunk-deletes
  4. Réactivez/recréez les index/contraintes sur la table cible (et vous pouvez peut-être différer certains d'entre eux, s'ils ne sont pas nécessaires pour toutes les opérations, et il est plus important de mettre les données de base en ligne rapidement).

Si vos partitions sont physiques et pas seulement logiques, vous pouvez gagner du temps en ayant différents processus remplir différentes partitions simultanément (bien sûr, cela signifie que vous ne pouvez pas utiliser TABLOCK/TABLOCKX). Cela suppose que la source convient également à plusieurs processus de sélection sans chevauchement/verrouillage, etc., et rend ce côté de l'opération encore plus lent (indice: créez un index clusterisé sur la source qui convient au schéma de partitionnement sur la destination).

Vous pouvez également considérer quelque chose de beaucoup plus primitif, comme BCP OUT/BCP IN .

Je ne sais pas que je passerais à SSIS pour aider avec cela. Il y a probablement des gains d'efficacité ici, mais je ne sais pas si l'effort justifie les économies.

26
Aaron Bertrand

En examinant votre problème du point de vue de SSIS, je pense que la raison pour laquelle cela a pris si longtemps est que vous n'aviez pas de traitement par lots. Cela peut entraîner un trop grand nombre de lignes remplissant le pipeline SSIS et peut en conséquence entraver vos performances SSIS. Ce que vous devez faire est de modifier vos lignes par paramètre de lot et éventuellement votre taille de validation d'insertion maximale. Maintenant, ce que vous définissez aussi dépendra de la quantité de mémoire disponible sur votre serveur SSIS? Quelle est la vitesse du disque de votre instance SQL Server? La meilleure façon de le faire est de tester. Permet par exemple d'utiliser 10 000. Cela enverra un lot au serveur 10 000 à la fois, empêchant ainsi votre pipeline de trop remplir et aidera à exécuter ce processus plus rapidement. Ces paramètres sont définis dans votre destination OLEDB.

OLEDB Destination

S'il s'agit d'un problème, vous pouvez également ajouter une tâche d'exécution SQL avant et après pour faire comme @AaronBertrand le suggère et supprimer/réajouter des index ou des contraintes à la table.

10
Zane