2010-01-06 7 views
1

D'abord, je sais que l'instruction SQL pour mettre à jour table_a en utilisant des valeurs de table_b est sous forme de:Performance de mettre à jour une grande table à l'aide des valeurs d'une petite table

Oracle:

UPDATE table_a 
    SET (col1, col2) = (SELECT cola, colb 
         FROM table_b 
         WHERE table_a.key = table_b.key) 
WHERE EXISTS (SELECT * 
       FROM table_b 
       WHERE table_a.key = table_b.key) 

MySQL :

UPDATE table_a 
INNER JOIN table_b ON table_a.key = table_b.key 
SET table_a.col1 = table_b.cola, 
    table_a.col2 = table_b.colb 

Ce que je comprends est le moteur de base de données passera par des enregistrements dans table_a et les mettre à jour avec les valeurs de correspondant enregistrements dans table_b.

Donc, si j'ai 10 millions de disques dans table_a et seulement 10 enregistrements table_b:

  1. Est-ce que cela signifie que le moteur va faire 10 millions d'itérations par table_a juste pour mettre à jour 10 dossiers? Est-ce que Oracle/MySQL/etc est assez intelligent pour faire seulement 10 itérations à travers table_b?

  2. Existe-t-il un moyen de forcer le moteur à parcourir réellement les enregistrements dans table_b au lieu de table_a pour effectuer la mise à jour? Existe-t-il une syntaxe alternative pour l'instruction sql?

On suppose que table_a.key et table_b.key sont indexées.

Répondre

3

L'un ou l'autre des moteurs doit être assez intelligent pour optimiser la requête en se basant sur le fait qu'il n'y a que dix lignes dans la table b. La façon dont le moteur détermine ce qu'il faut faire est basée sur des facteurs tels que les index et les statistiques.

Si la colonne "clé" est la clé primaire et/ou est indexée, le moteur devra faire très peu de travail pour exécuter cette requête. Il va en quelque sorte déjà "savoir" où se trouvent les lignes correspondantes, et les rechercher très rapidement. Il n'aura pas à "itérer" du tout.

S'il n'y a pas d'index sur la colonne de clé, le moteur devra effectuer une "analyse de table" (à peu près l'équivalent de "itérer") pour trouver les bonnes valeurs et les faire correspondre. Cela signifie qu'il devra parcourir 10 millions de lignes. Faites une petite lecture sur ce qu'on appelle un plan d'exécution. Ceci est essentiellement une explication du travail que le moteur a dû faire pour exécuter votre requête (certaines bases de données l'affichent uniquement en texte, d'autres ont la possibilité de la voir graphiquement). Apprendre à interpréter un plan d'exécution vous donnera un bon aperçu de l'ajout d'index à vos tables et de l'optimisation de vos requêtes.

Regardez ces up si elles ne fonctionnent pas (il a été un certain temps), mais il est quelque chose comme:

  • En MySQL, mettre le travail « EXPLIQUER » devant votre instruction SELECT
  • Dans Oracle, exécutez "SET AUTOTRACE ON" avant d'exécuter votre instruction SELECT

Je pense que la première requête (Oracle) serait mieux écrite avec un JOIN au lieu d'un WHERE EXISTS. Le moteur peut être assez intelligent pour l'optimiser de toute façon. Une fois que vous avez compris le plan d'exécution, vous pouvez l'exécuter dans les deux sens et voir par vous-même.:)

+0

En fait, IN/EXISTS est mieux dans Oracle que d'utiliser un JOIN (selon les critères appropriés): http://explainextended.com/2009/09/30/in-vs- join-vs-exists-oracle/ –

+0

Intéressant. Le HACH JOIN SEMI est une optimisation intelligente. Bien que cela semble seulement important si la colonne n'est pas indexée. J'utiliserais probablement encore un JOIN qui échouerait (plus d'IMHO expressif). Mais certainement utile de savoir pour certains cas! –

1

D'accord, je sais répondre propre question est généralement mal vus, mais je l'ai déjà accepté une autre réponse et ne ici donc non acceptable meh .. il est

J'ai découvert une bien meilleure alternative que je J'aime partager avec quelqu'un qui rencontre le même scénario: MERGE déclaration.

Apparemment, les versions Oracle plus récentes ont introduit cette déclaration MERGE qui souffle simplement! Non seulement que la performance est tellement mieux dans la plupart des cas, la syntaxe est si simple et si logique que je me sens stupide d'utiliser l'instruction UPDATE! Ici vient ..

MERGE INTO table_a 
USING table_b 
ON (table_a.key = table_b.key) 
WHEN MATCHED THEN UPDATE SET 
    table_a.col1 = table_b.cola, 
    table_a.col2 = table_b.colb; 

Et plus est que je peux aussi prolonger la déclaration d'inclure INSERT action lorsque table_a n'a pas les enregistrements correspondants pour certains enregistrements table_b:

MERGE INTO table_a 
USING table_b 
ON (table_a.key = table_b.key) 
WHEN MATCHED THEN UPDATE SET 
    table_a.col1 = table_b.cola, 
    table_a.col2 = table_b.colb 
WHEN NOT MATCHED THEN INSERT 
    (key, col1, col2) 
    VALUES (table_b.key, table_b.cola, table_b.colb); 

Ce nouveau type de déclaration fait ma journée le jour où je l'ai découvert :)

Questions connexes