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

27

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 une charge rapide active) 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 de RAM sur le serveur), ce qui me semble très lent.

nojetlag
la source
1
Les partitions sont-elles sur des groupes de fichiers séparés (et se trouvent-elles sur ces groupes de fichiers sur différents disques physiques)?
Aaron Bertrand
3
Une très bonne ressource The Data Loading Performance Guide . Cela concerne beaucoup d'optimisation des performances que vous pouvez faire, par exemple , activer TF610 , utiliser BCP OUT / IN, SSIS, etc. Il vous suffit de suivre les recommandations et de le tester dans votre environnement.
Kin Shah
@Aaron oui, par mois, un groupe de fichiers, 12 san lun sont attachés, donc tous les jan vont sur un lun, etc. Je ne sais pas combien de disques par lun mais il devrait y en avoir beaucoup.
nojetlag
Oui, je voulais vraiment dire "ensembles de disques" et j'aurais probablement pu mentionner aussi les contrôleurs, qui peuvent devenir saturés.
Aaron Bertrand
@Kin a consulté le guide, mais il semble obsolète: "La destination SQL Server est le moyen le plus rapide de charger en bloc des données à partir d'un flux de données Integration Services vers SQL Server. Cette destination prend en charge toutes les options de chargement en bloc de SQL Server - à l'exception de ROWS_PER_BATCH . " et dans SSIS 2012, ils recommandent la destination OLE DB pour de meilleures performances.
nojetlag

Réponses:

25

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 nlignes, ce qui peut réduire la pression sur le journal des transactions, et signifie bien sûr que si un lot échoue, vous n'avez qu'à démarrer à partir de ce lot. J'ai blogué à ce sujet (bien 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.

Aaron Bertrand
la source
2
Ne supprimez pas aveuglément les index (en particulier les index clusterisés) si vos données ne sont pas triées. La suppression de l'index et l'attente de recréer un index clusterisé peuvent être une énorme erreur car cela peut coûter à la fois un espace disque énorme et une énorme quantité de temps. Je ne suis pas le premier à rencontrer une telle erreur. Regardez la description du "Plan B" dans cet article sqlmag.com/t-sql/… . L'auteur avait le même problème.
jyao
10

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 nuire à 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.

Destination OLEDB

Si c'est 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 tous les index ou contraintes à la table.

Zane
la source
1
Il y a une excellente question sur ce qu'implique une «charge rapide» ailleurs sur DBA.SE: dba.stackexchange.com/questions/141430/… .
Jon of All Trades