Mettre à jour toutes les lignes

12

Je veux connaître la manière la plus efficace de mettre à jour chaque ligne d'une table Oracle extrêmement grande pour une seule colonne. Par exemple:

update mytable set mycolumn=null;

ou:

update mytable set mycolumn=42;

Ma connaissance peut très bien être périmée. Ce que je fais, c'est modifier le tableau pour supprimer la colonne. Ensuite, je modifie le tableau pour ajouter la colonne avec une valeur par défaut de la nouvelle valeur que je veux utiliser. Ensuite, je modifie le tableau pour supprimer la valeur par défaut de la colonne. Je trouve que c'est beaucoup plus rapide que de simplement exécuter une mise à jour, mais j'ai le sentiment qu'il existe une meilleure méthode.

kainaw
la source
Si je comprends bien, l'ajout d'une nouvelle colonne non nulle avec une valeur par défaut est un changement de métadonnées uniquement dans Oracle. Je doute qu'ils auront optimisé le cas "mettre à jour toutes les lignes à la même valeur". Est-ce une opération courante pour vous?
Martin Smith
1
Essayez simplement les deux méthodes et chronométrez-les. Qu'est-ce qui vous empêche de faire ça? Voyez le fait que vous devez finir avec le même résultat, pas avec un résultat différent! Sinon, la comparaison n'est pas valide.
tvCa
@tvCa J'ai essayé dans les deux sens. Si je fais juste une mise à jour, elle fonctionne pendant environ deux heures, puis je la tue. Si je laisse tomber une colonne, cela ne prend que quelques secondes. L'ajout d'une colonne sans valeur par défaut (qui annule la colonne) ne prend que quelques secondes. L'ajout d'une colonne avec une valeur par défaut prend environ 30 minutes. Donc, si je veux, par exemple, définir toutes les valeurs d'une colonne sur «Some Value», je supprime et ajoute actuellement la colonne. Je veux juste savoir s'il existe un moyen plus rapide de le faire.
kainaw
2
Utilisez-vous 11gR2? @MartinSmith est correct. Voir ici pour une description de la façon dont l'ajout de la nouvelle colonne avec un DEFAULT comme NOT NULL est un changement beaucoup plus rapide que l'ajout comme NULL, ce qui forcera une mise à jour de toutes les lignes de la table (tout comme l'émission d'une instruction UPDATE le fera). Le problème que je vois est la suppression de la valeur DEFAULT par la suite, car l'augmentation des performances provient du stockage du DEFAULT dans le dictionnaire. Vous devrez également gérer la contrainte NOT NULL à ce stade.
ansible

Réponses:

2

Cela dépend beaucoup de l'autre activité en cours contre ce tableau pendant que vous effectuez cette mise à jour en masse. J'espère que vous avez une sorte d'environnement de test où vous pouvez exécuter des échantillons de ce que vous aimeriez faire et avoir une idée de la meilleure façon. Je voudrais essayer:

  1. Exécutez le single update table set column_name = blah;
  2. Créez une boucle plSql pour sélectionner toutes les clés primaires de la table et parcourez-les, updating the column=blahet validez toutes les mises à jour X (peut-être 10000). Vous pouvez paralléliser ce code en le copiant et en le faisant copier dans une section distincte des clés primaires.

Nous avons eu un problème très similaire avec une table qui était très activement utilisée dans le système OLTP et nous avons pu la paralléliser 5 fois et fonctionner sans impact de verrouillage utilisateur sur une table de lignes de 100+ MM validée tous les 10000. Vous n'avez pas dit comment votre table est grande ou quel type d'application vous exécutez, mais ce type de solution peut vous convenir.

Pete Hagerty
la source
0

Pour un jeûne UPDATE, assurez-vous que vous n'avez aucun déclencheur qui se déclenche.

SELECT trigger_name, status FROM user_triggers WHERE table_name = 'MYTABLE';

ALTER TABLE mytable DISABLE ALL TRIGGERS;

Assurez-vous de ne réactiver que ceux que vous souhaitez lorsque vous avez terminé.

ALTER TRIGGER mytrigger ENABLE;

Vous pourriez également être confronté à la surcharge de la maintenance d'index. Essayez de reconstruire vos index séparément. Pour ce faire, la réponse ici par pappes devrait être utile: /programming/129046/disable-and-later-enable-all-table-indexes-in-oracle

Je répète la réponse de Pappes ici pour référence. (Notez que cette commande SPOOL émet des hypothèses sur votre plate-forme et votre environnement.)

set pagesize 0    
alter session set skip_unusable_indexes = true;
spool c:\temp\disable_indexes.sql
select 'alter index ' || u.index_name || ' unusable;' from user_indexes u;
spool off
@c:\temp\disable_indexes.sql

Importez ...

select 'alter index ' || u.index_name || ' rebuild online;'
  from user_indexes u;
durette
la source
-1

supprimer l'index. mettre à jour la colonne. renvoyer l'index. mais si la colonne contient une seule et même valeur pour toutes les lignes, vous pouvez supprimer l'index.

tatskie
la source
-2

Si vous n'avez pas de limitation d'espace, vous pouvez créer une nouvelle table, la même que votre table avec votre nouvelle colonne ajoutée à cette table et supprimer l'ancienne table:

create new_table as
select old_table.*, (with or without default_Value) as new_column
from old_table;
E_Salamon
la source
1
Est-ce que cela sera plus efficace? Pourquoi? Et si des FK font référence à la table existante?
ypercubeᵀᴹ
oui, vous pouvez l'essayer sur un autre exemple de table et voir le résultat vous-même. S'il y a des FK, je ne sais pas exactement mais vous pouvez les désactiver et les activer si c'est efficace.
E_Salamon
-3

Essayez plusieurs séquences de mise à jour / validation. L'insertion / la mise à jour / la suppression d'un trop grand nombre de lignes sans validation entraîne une lourde charge d'E / S. Il peut être assez optimisé en connaissant les tailles de bloc et les tailles d'enregistrement et d'autres choses.

Pour supprimer des données entières sur une table, truncate table xc'est mieux que delete from x. La purge crée également une autre charge de travail de processus.

Modifier: Vous pouvez utiliser l' inmemoryoption, charger la table en mémoire au format en colonnes, puis faire la mise à jour. cela dépend vraiment des relations et de la structure de votre base de données. Consultez cet article .

Ruse
la source
3
Ils veulent mettre à jour une colonne du tableau. Je ne vois pas en quoi truncateou deleteserait d'aucune aide.
ypercubeᵀᴹ
@ypercube Je viens d'expliquer comment la manipulation de plusieurs données sans validation conduit à une charge d'E / S indésirable; soit mise à jour ou autres OLTP.
Cunning
3
Pourriez-vous expliquer à quelle fréquence les validations réduisent les E / S? Ne serait - ils augmenter les E / S en raison des points de contrôle?
mustaccio
3
Votre utilisation de la terminologie non conventionnelle ("tx journal", "flushes your session") est un peu déroutante. Que vous utilisiez plusieurs transactions courtes ou une transaction massive, le volume total des enregistrements de rétablissement générés sera le même. Les opérations d'E / S ne se produisent que lorsque le tampon du journal de rétablissement est écrit sur le disque (en laissant pour l'instant les points de contrôle du cache du tampon), ce qui se produit lors de la validation ou lorsque le tampon de rétablissement est presque plein. Par la suite, si vous vous engagez fréquemment, vous provoquez des E / S supplémentaires, donc je me demande comment cela peut réduire les E / S.
mustaccio du
4
Vous pouvez lire ce que Tom Kyte dit au sujet de « commits fréquentes »: asktom.oracle.com/pls/apex/... « est faux, faux, faux si mal .... Donc , très très mal. »
a_horse_with_no_name