Als je een enorme . zou hebben problemen met je aanpak, je mist zeer waarschijnlijk een index in de kolom clean.id
, dat is vereist voor uw benadering wanneer de MERGE
gebruikt dual
als bron voor elke rij.
Dit is minder waarschijnlijk als je de id
. zegt is een primaire sleutel .
Dus in principe je denkt goed na en je ziet uitvoeringsplan vergelijkbaar met die hieronder:
---------------------------------------------------------------------------------------------------
| 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)
Het uitvoeringsplan is dus prima en werkt effectief, maar er is één probleem.
Onthoud je gebruikt altijd een index, je zult blij zijn als je een paar rijen verwerkt, maar het schaalt niet .
Als u een miljoenen . verwerkt van records, kunt u terugvallen op een verwerking in twee stappen,
-
voeg alle rijen in een tijdelijke tabel in
-
voer een enkele
MERGE
. uit statement met behulp van de tijdelijke tabel
Het grote voordeel is dat Oracle een hash join
. kan openen en verwijder de indextoegang voor elk van de miljoen rijen.
Hier een voorbeeld van een test van de clean
tabel gestart met 1M id
(niet getoond) en het uitvoeren van 1M insert en 1M updates:
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)
De test loopt in ca. 10 seconden, wat minder is dan de helft van jullie nadert met MERGE
met behulp van dual
.
Als dit nog steeds niet genoeg is, moet u de parallelle optie . gebruiken .