Wenn Sie eine massive hätten Probleme mit Ihrer Vorgehensweise haben, fehlt Ihnen sehr wahrscheinlich ein Index auf der Spalte clean.id
, die für Ihren Ansatz beim MERGE
erforderlich ist verwendet dual
als Quelle für jede Zeile.
Dies ist weniger wahrscheinlich, während Sie die id
sagen ist ein Primärschlüssel .
Also im Grunde Sie denken richtig und Sie werden den Ausführungsplan sehen ähnlich wie unten:
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------
| 0 | MERGE STATEMENT | | | | 2 (100)| |
| 1 | MERGE | CLEAN | | | | |
| 2 | VIEW | | | | | |
| 3 | NESTED LOOPS OUTER | | 1 | 40 | 2 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL | DUAL | 1 | 2 | 2 (0)| 00:00:01 |
| 5 | VIEW | VW_LAT_A18161FF | 1 | 38 | 0 (0)| |
| 6 | TABLE ACCESS BY INDEX ROWID| CLEAN | 1 | 38 | 0 (0)| |
|* 7 | INDEX UNIQUE SCAN | CLEAN_UX1 | 1 | | 0 (0)| |
---------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
7 - access("CLEAN"."ID"=:ID)
Der Ausführungsplan ist also in Ordnung und funktioniert effektiv, aber er hat ein Problem.
Denken Sie daran, wenn Sie immer einen Index verwenden, werden Sie glücklich sein, wenn Sie nur wenige Zeilen verarbeiten, aber er wird nicht skaliert .
Wenn Sie Millionen verarbeiten von Datensätzen können Sie auf eine zweistufige Verarbeitung zurückgreifen,
-
füge alle Zeilen in eine temporäre Tabelle ein
-
Führen Sie ein einzelnes
MERGE
durch Anweisung unter Verwendung der temporären Tabelle
Der große Vorteil ist, dass Oracle einen hash join
öffnen kann und den Indexzugriff für jede der Millionen loszuwerden Zeilen.
Hier ein Beispiel für einen Test des clean
Tabelle initiiert mit 1M id
(nicht gezeigt) und Durchführen von 1 Mio. Einfügung und 1 Mio. Aktualisierungen:
n = 1000000
data2 = [{"id" : i, "xcount" :1} for i in range(2*n)]
sql3 = """
insert into tmp (id,count)
values (:id,:xcount)"""
sql4 = """MERGE into clean USING tmp on (clean.id = tmp.id)
when not matched then insert (id, count) values (tmp.id, tmp.count)
when matched then update set clean.count= clean.count + tmp.count"""
cursor.executemany(sql3, data2)
cursor.execute(sql4)
Der Test läuft in ca. 10 Sekunden, das ist weniger als die Hälfte Ihrer Annäherung mit MERGE
mit dual
.
Wenn dies immer noch nicht ausreicht, müssen Sie die parallele Option verwenden .