Aktualisieren Sie alle Zeilen


12

Ich möchte die effizienteste Methode zum Aktualisieren jeder Zeile in einer extrem großen Oracle-Tabelle für eine einzelne Spalte kennen. Beispielsweise:

update mytable set mycolumn=null;

oder:

update mytable set mycolumn=42;

Mein Wissen kann sehr gut abgestanden sein. Ich ändere die Tabelle, um die Spalte zu löschen. Anschließend ändere ich die Tabelle, um die Spalte mit dem Standardwert des neuen Werts hinzuzufügen, den ich verwenden möchte. Dann ändere ich die Tabelle, um den Standardwert für die Spalte zu entfernen. Ich finde, dass dies viel schneller ist, als nur ein Update auszuführen, aber ich habe das Gefühl, dass es eine bessere Methode gibt.


Soweit ich weiß, ist das Hinzufügen einer neuen Nicht-Null-Spalte mit einem Standardwert nur eine Metadatenänderung in Oracle. Ich bezweifle, dass sie den Fall "alle Zeilen auf den gleichen Wert aktualisieren" optimiert haben. Ist das eine gemeinsame Operation für Sie?
Martin Smith

1
Probieren Sie einfach beide Methoden aus und messen Sie sie. Was hindert Sie daran? Beachten Sie, dass Sie mit demselben Ergebnis enden müssen, nicht mit einem anderen! Andernfalls ist der Vergleich ungültig.
tvCa

@tvCa Ich habe beide Möglichkeiten ausprobiert. Wenn ich nur ein Update mache, läuft es ungefähr zwei Stunden und dann töte ich es. Wenn ich eine Spalte fallen lasse, dauert es nur ein paar Sekunden. Das Hinzufügen einer Spalte ohne Standardwert (der die Spalte auf null setzt) ​​dauert nur wenige Sekunden. Das Hinzufügen einer Spalte mit einem Standardwert dauert ca. 30 Minuten. Wenn ich zum Beispiel alle Werte in einer Spalte auf "Ein Wert" setzen möchte, füge ich die Spalte derzeit hinzu. Ich möchte nur wissen, ob es einen schnelleren Weg gibt.
Kainaw

2
Verwenden Sie 11gR2? @MartinSmith ist korrekt. Hier finden Sie eine Beschreibung, wie das Hinzufügen der neuen Spalte mit einem DEFAULT als NOT NULL eine viel schnellere Änderung ist als das Hinzufügen als NULL, wodurch eine Aktualisierung aller Zeilen in der Tabelle erzwungen wird (genau wie das Ausgeben einer UPDATE-Anweisung). Das Problem, das ich sehe, besteht darin, den DEFAULT-Wert später zu entfernen, da die Leistungssteigerung durch das Speichern des DEFAULT-Werts im Wörterbuch erfolgt. An diesem Punkt müssen Sie sich auch mit der NOT NULL-Einschränkung befassen.
Ansible

Antworten:


2

Viel hängt von der anderen Aktivität ab, die gegen diese Tabelle ausgeführt wird, während Sie dieses Massenupdate durchführen. Ich hoffe, Sie haben eine Art Testumgebung, in der Sie einige Beispiele für das, was Sie tun möchten, ausführen und eine Vorstellung davon bekommen können, welcher Weg der beste ist. Ich würde versuchen:

  1. Führe die Single aus update table set column_name = blah.
  2. Erstellen Sie eine plSql-Schleife, um alle Primärschlüssel in der Tabelle auszuwählen, diese zu durchlaufen updating the column=blahund alle X-Aktualisierungen (möglicherweise 10000) festzuschreiben . Sie können diesen Code parallelisieren, indem Sie ihn kopieren und in einem separaten Abschnitt der Primärschlüssel kopieren.

Wir hatten ein sehr ähnliches Problem mit einer Tabelle, die sehr aktiv im OLTP-System verwendet wurde, und wir konnten sie 5x parallelisieren und alle 10000 Zeilen ohne Auswirkung auf die Benutzersperrung auf eine 100+ MM-Zeilentabelle ausführen. Sie haben nicht angegeben, wie Groß ist Ihr Tisch oder welche Art von Anwendung Sie ausführen, aber diese Art von Lösung könnte zu Ihnen passen.


0

UPDATEStellen Sie sicher, dass Sie für ein schnelles keine Trigger haben, die feuern.

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

ALTER TABLE mytable DISABLE ALL TRIGGERS;

Stellen Sie sicher, dass Sie nur diejenigen wieder aktivieren, die Sie möchten, wenn Sie fertig sind.

ALTER TRIGGER mytrigger ENABLE;

Möglicherweise fällt auch der Aufwand für die Indexpflege an. Versuchen Sie, Ihre Indizes separat neu zu erstellen. Hierfür ist die Antwort von pappes hilfreich: /programming/129046/disable-and-later-enable-all-table-indexes-in-oracle

Ich wiederhole die Antwort von pappes hier als Referenz. (Beachten Sie, dass dieser SPOOL-Befehl Annahmen über Ihre Plattform und Umgebung macht.)

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

Importieren ...

select 'alter index ' || u.index_name || ' rebuild online;'
  from user_indexes u;

-1

entferne den Index. Aktualisieren Sie die Spalte. Liefert den Index zurück. Wenn die Spalte jedoch denselben Wert für alle Zeilen enthält, können Sie den Index löschen.


-2

Wenn Sie keine Speicherplatzbeschränkung haben, können Sie eine neue Tabelle erstellen, genauso wie Ihre Tabelle mit der neuen Spalte, die dieser Tabelle hinzugefügt wurde, und die alte Tabelle löschen:

create new_table as
select old_table.*, (with or without default_Value) as new_column
from old_table;

1
Wird dies effizienter? Warum? Und was ist, wenn es FKs gibt, die auf die vorhandene Tabelle verweisen?
Ypercubeᵀᴹ

ja, Sie können es an einer anderen Beispieltabelle versuchen und das Ergebnis selbst sehen. Wenn es FKs gibt, weiß ich nicht genau, aber Sie können sie deaktivieren und aktivieren, wenn es effizient ist.
E_Salamon

-3

Probieren Sie mehrere Aktualisierungs- / Festschreibungssequenzen aus. Das Einfügen / Aktualisieren / Löschen zu vieler Zeilen ohne Festschreibung führt zu einer hohen E / A-Belastung. Es kann ziemlich optimiert werden, wenn man Blockgrößen, Datensatzgrößen und so weiter kennt.

Zum Löschen ganzer Daten in einer Tabelle truncate table xist besser als delete from x. Auch das Löschen führt zu einer anderen Prozessauslastung.

Bearbeiten: Sie können die inmemoryOption verwenden, um die Tabelle in den Speicher im Spaltenformat zu laden und dann das Update durchzuführen. es hängt wirklich von den Beziehungen und der Struktur Ihrer DB ab. Siehe diesen Artikel .


3
Sie möchten eine Spalte der Tabelle aktualisieren. Ich verstehe nicht, wie truncateoder wie ich deletehelfen könnte.
ypercubeᵀᴹ

@ypercube Ich habe gerade erklärt, wie mehrfache Datenmanipulation ohne Festschreibung zu unerwünschter E / A-Last führt. entweder Update oder andere OLTPs sein.
Schlaue

3
Können Sie erklären, wie häufig Commits die E / A reduzieren ? Würden sie die E / A nicht aufgrund von Checkpoints erhöhen ?
Mustaccio

3
Ihre Verwendung unkonventioneller Terminologie ("tx journal", "flushes your session") ist etwas verwirrend. Unabhängig davon, ob Sie mehrere kurze Transaktionen oder eine massive Transaktion verwenden, bleibt das Gesamtvolumen der generierten Wiederholungsdatensätze gleich. E / A-Vorgänge treten nur auf, wenn der Redo-Log-Puffer auf die Festplatte geschrieben wird (ohne Puffer-Cache-Checkpoints). Dies geschieht beim Festschreiben oder wenn der Redo-Puffer fast voll ist. Wenn Sie anschließend häufig Commits ausführen, verursachen Sie zusätzliche E / A. Daher frage ich mich, wie dadurch die E / A verringert werden können .
Mustaccio

4
Vielleicht möchten Sie lesen, was Tom Kyte zu "häufigen Commits" zu sagen hat: asktom.oracle.com/pls/apex/… " ist falsch, falsch, falsch. So falsch ... so sehr falsch "
a_horse_with_no_name
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.