Om du skulle ha en massiv problem med ditt tillvägagångssätt saknar du mycket troligt ett index i kolumnen clean.id
, som krävs för din strategi när MERGE
använder dual
som källa för varje rad.
Detta är mindre troligt när du säger id
är en primär nyckel .
Så i princip du tänker rätt och du kommer att se utförandeplan liknande den nedan:
---------------------------------------------------------------------------------------------------
| 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)
Så genomförandeplanen är bra och fungerar effektivt, men den har ett problem.
Kom ihåg att du alltid använder ett index, du kommer att vara nöjd när du bearbetar några rader, men det kommer inte att skalas .
Om du bearbetar en miljoner av poster kan du falla tillbaka till en tvåstegsbearbetning,
-
infoga alla rader i en tillfällig tabell
-
utför en enda
MERGE
uttalande med den temporära tabellen
Den stora fördelen är att Oracle kan öppna en hash join
och bli av med indexåtkomsten för var och en av miljonerna rader.
Här ett exempel på ett test av clean
tabell initierad med 1M id
(visas inte) och utför 1M infogning och 1M uppdateringar:
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)
Testet pågår i ca. 10 sekunder, vilket är mindre än hälften av dig närmar dig med MERGE
med dual
.
Om detta fortfarande inte räcker måste du använda parallellt alternativ .