METTRE À JOUR avec JOIN sur des enregistrements de 100 mm, comment faire mieux? (en T-SQL)

11

J'ai besoin de mettre à jour 100 millions d'enregistrements dans une seule table, en effet, normalisant la table en remplaçant la valeur varchar d'une colonne par un simple ID. (Je dis «remplacer» mais j'écris vraiment l'ID dans une autre colonne.)

Ce que j'essaie de réaliser, c'est de normaliser l'ensemble de données. Les données non encore normalisées n'ont pas d'indexation. Ma pensée était que je ne construirais pas d'index sur les valeurs brutes, en attendant, au lieu d'indexer les clés étrangères qui remplaceraient les valeurs varchar par des valeurs tinyint une fois la mise à jour terminée.

UPDATE A
SET A.AutoClassID = B.AutoClassID
FROM AutoDataImportStaging.dbo.Automobile as A
JOIN AutoData.dbo.AutoClass as B on (A.AutoClassName = B.AutoClassName)

Contexte

  • à l'aide de MSSQL 2008 R2 sur Server 2008 R2
  • le serveur a 8 Go de RAM
  • le serveur a un RAID10, 7200 RPM SATA (pas génial, je sais, en production, cela ne lira que les données et non les données; plus la récente pénurie HD a rendu cela nécessaire pour le coût)
  • le serveur a un processeur Xeon quadricœur double
  • la machine ne fait rien d'autre (actuellement dédiée au développement, seulement ce processus)
  • la journalisation simple est activée (? - mais est-elle toujours enregistrée pour pouvoir être annulée?)
  • notez que la requête fait référence à deux bases de données différentes, pour ce que cela vaut
  • la "largeur" ​​d'un enregistrement dans le tableau mis à jour est de 455 octets

Ressources pendant l'exécution

  • la RAM physique est au maximum
  • les E / S de disque sont au maximum
  • Le CPU ne fait pratiquement rien (le point d'étranglement est les E / S)
  • le temps d'exécution a été de 14 heures et ça compte!

Je soupçonne quelques choses comme j'ai besoin d'un index sur les données brutes, même si je vais supprimer la colonne (AutoClassName) après les mises à jour de normalisation. Je me demande également si je devrais simplement parcourir le tableau un enregistrement à la fois au lieu de JOIN, ce qui semblait ridicule au moment où j'ai commencé cela, mais maintenant il semble que cela aurait été plus rapide.

Comment dois-je changer ma méthodologie pour mes mises à jour de normalisation restantes (similaires à celle-ci) plus rapidement?

Chris Adragna
la source

Réponses:

7

Vous essayez de le faire comme une transaction unique (très importante). Effectuez plutôt la mise à jour par lots plus petits.

Vous bénéficierez également de:

  • Un index temporaire sur AutoData.dbo.AutoClass.AutoClassName
  • Plus de RAM. Beaucoup plus de RAM.
Mark Storey-Smith
la source
1
+1 Je suis d'accord avec la mise à jour par lots en utilisant la TOPclause. Ce serait mon approche.
Thomas Stringer
Si je mets UPDATE TOP, j'ai besoin d'une clause WHERE (WHERE AutoClassID est NULL)? La clause WHERE n'introduirait-elle pas un nouveau hit de performance (un scan de table que je ne fais pas maintenant). Sans aucun doute, cela diminuerait le problème de RAM que j'ai avec le JOIN.
Chris Adragna
Ma réponse est attendue depuis longtemps, mais dans mon cas, SET ROWCOUNT s'est avéré être le plus efficace.
Chris Adragna
10

Je prendrais une approche différente.

Au lieu de mettre à jour les tables existantes, créez simplement une nouvelle table contenant ce dont vous avez besoin.

Ce sera certainement plus rapide:

SELECT DISTINCT
    AutoClassID,
    <Other fields>
INTO
    AutoDataImportStaging.dbo.Automobile
FROM
    AutoData.dbo.AutoClass

Tel qu'il est actuellement écrit, de nombreuses opérations logiques se produisent:

  • Lire toutes les valeurs de A.AutoClassName
  • Lire toutes les valeurs de B.AutoClassName
  • Comparer les valeurs A et B
  • De l'ensemble correspondant, lisez toutes les valeurs de B.AutoClassID
  • Mettre à jour les valeurs existantes de A.AutoClassId pour qu'elles soient la valeur B.AutoClassId à travers les index existants
JNK
la source
Cela ressemble à une approche simple et agréable, surtout compte tenu du problème d'E / S du disque que je rencontre. Merci d'avoir répondu si rapidement.
Chris Adragna
1
Je vous suggère de vérifier à nouveau que vous disposez de suffisamment d'espace libre dans votre journal et vos fichiers de données. Si les fichiers se développent automatiquement, les performances seront en baisse. Je vois souvent des gens exécuter une grosse mise à jour ponctuelle et augmenter automatiquement leur fichier journal sans s'en rendre compte.
darin strait
5

Faire une boucle dans le tableau une ligne à la fois, ne sera pas plus rapide!

Comme suspecté et confirmé par vous, cela sera lié aux E / S - ayant un disque, les lectures, les écritures, les journaux de transactions et (tout) l'espace de travail temporaire seront tous en concurrence pour les mêmes E / S.

Une récupération simple enregistrera toujours les transactions, mais le journal sera effacé par un point de contrôle. Il est possible que la taille initiale du journal et les paramètres de croissance automatique entraînent un ralentissement des E / S - le journal des transactions devra augmenter pour s'adapter aux modifications.

Avez-vous essayé d'indexer le champ AutoClassName? Combien de valeurs AutoClass différentes existe-t-il?

Vous devrez peut-être regrouper les mises à jour, en fonction des limites de vos E / S. Alors mettez à jour 1 million, checkpoint, répétez ....

Kev Riley
la source
Il n'y a que 15 valeurs AutoClass différentes. Vos commentaires confirment bon nombre de mes soupçons (et douleurs!). Merci d'avoir répondu.
Chris Adragna
3

Créez des index pour les champs de jonction.

Vous pouvez toujours supprimer les index lorsque vous avez terminé.

Je serais très surpris si les index n'amélioraient pas significativement les performances de la mise à jour.

Jimbo
la source
Je suis sûr que les index s'amélioreraient. Je suppose que la question est de savoir s'ils s'améliorent plus que le temps qu'il faut pour créer l'index (pour une seule utilisation). Probablement oui. :)
Chris Adragna
3

Exportez comme vous le souhaitez, créez une nouvelle table et réimportez. En prime, vous auriez une copie des données en tant que sauvegarde, si des miracles se produisaient.

srini.venigalla
la source