web-dev-qa-db-fra.com

Moyen efficace de mettre à jour toutes les lignes d'une table

J'ai une table avec beaucoup d'enregistrements (peut-être plus de 500 000 ou 1 000 000). J'ai ajouté une nouvelle colonne dans cette table et je dois renseigner une valeur pour chaque ligne de la colonne, en utilisant la valeur de ligne correspondante d'une autre colonne de cette table.

J'ai essayé d'utiliser des transactions distinctes pour sélectionner chaque prochain bloc de 100 enregistrements et mettre à jour leur valeur, mais cela prend néanmoins des heures pour mettre à jour tous les enregistrements dans Oracle10, par exemple.

Quel est le moyen le plus efficace de le faire en SQL, sans utiliser certaines fonctionnalités spécifiques au dialecte, afin que cela fonctionne partout (Oracle, MSSQL, MySQL, PostGre, etc.)?

INFORMATIONS SUPPLÉMENTAIRES: Il n'y a pas de champs calculés. Il y a des index. Utilisé les instructions SQL générées qui mettent à jour le tableau ligne par ligne.

32
m_pGladiator

La méthode habituelle consiste à utiliser UPDATE:

UPDATE mytable
   SET new_column = <expr containing old_column>

Vous devriez pouvoir faire ceci est une transaction simple.

49
Marcelo Cantos

Comme le suggère Marcelo:

UPDATE mytable
SET new_column = <expr containing old_column>;

Si cela prend trop de temps et échoue en raison d'erreurs "capture instantanée trop ancienne" (par exemple, si l'expression interroge une autre table très active), et si la nouvelle valeur de la colonne est toujours NOT NULL, vous pouvez mettre à jour la table par lots:

UPDATE mytable
SET new_column = <expr containing old_column>
WHERE new_column IS NULL
AND ROWNUM <= 100000;

Il suffit d’exécuter cette instruction, COMMIT, puis de la réexécuter; rincer, répéter jusqu'à ce que "0 rangées soient mises à jour". Cela prendra plus de temps, mais chaque mise à jour risque moins d'échouer.

MODIFIER:

Une meilleure alternative qui devrait être plus efficace consiste à utiliser l'API DBMS_PARALLEL_EXECUTE.

Exemple de code (à partir de la documentation Oracle):

DECLARE
  l_sql_stmt VARCHAR2(1000);
  l_try NUMBER;
  l_status NUMBER;
BEGIN

  -- Create the TASK
  DBMS_PARALLEL_EXECUTE.CREATE_TASK ('mytask');

  -- Chunk the table by ROWID
  DBMS_PARALLEL_EXECUTE.CREATE_CHUNKS_BY_ROWID('mytask', 'HR', 'EMPLOYEES', true, 100);

  -- Execute the DML in parallel
  l_sql_stmt := 'update EMPLOYEES e 
      SET e.salary = e.salary + 10
      WHERE rowid BETWEEN :start_id AND :end_id';
  DBMS_PARALLEL_EXECUTE.RUN_TASK('mytask', l_sql_stmt, DBMS_SQL.NATIVE,
                                 parallel_level => 10);

  -- If there is an error, RESUME it for at most 2 times.
  l_try := 0;
  l_status := DBMS_PARALLEL_EXECUTE.TASK_STATUS('mytask');
  WHILE(l_try < 2 and l_status != DBMS_PARALLEL_EXECUTE.FINISHED) 
  LOOP
    l_try := l_try + 1;
    DBMS_PARALLEL_EXECUTE.RESUME_TASK('mytask');
    l_status := DBMS_PARALLEL_EXECUTE.TASK_STATUS('mytask');
  END LOOP;

  -- Done with processing; drop the task
  DBMS_PARALLEL_EXECUTE.DROP_TASK('mytask');

END;
/

Oracle Docs: https://docs.Oracle.com/database/121/ARPLS/d_parallel_ex.htm#ARPLS67333

8
Jeffrey Kemp

Vous pouvez supprimer tous les index de la table, puis effectuer votre insertion, puis recréer les index.

2
Timothy

mise à jour des hôtels set Discount = 30 où Hotelid> = 1 et Hotelid <= 5504

0
user3098137

Cela ne vous conviendra peut-être pas, mais une technique que j’ai utilisée plusieurs fois dans le passé pour des circonstances similaires.

créé updated_ {nom_table}, puis sélectionnez l’insertion par lots dans cette table. Une fois terminé, ceci dépend de la capacité de Oracle (que je ne connais ni n’utilise) à renommer les tables de manière atomique. updated_ {nom_table} devient {nom_table}, tandis que {nom_table} devient original_ {nom_table}.

La dernière fois que je devais le faire, c'était pour une table fortement indexée avec plusieurs millions de lignes qui ne pouvaient absolument pas être verrouillées pour la durée nécessaire pour y apporter des changements sérieux.

0
David

Quelle est la version de la base de données? Découvrez les colonnes virtuelles en 11g:

Ajout de colonnes avec une valeur par défaut http://www.Oracle.com/technology/pub/articles/Oracle-database-11g-top-features/11g-schemamanaman.html

0
Stellios