sql >> Database teknologi >  >> RDS >> Oracle

Er der en måde at forbedre en MERGE-forespørgsel på?

Hvis du ville have en massiv problemer med din tilgang, mangler du sandsynligvis et indeks i kolonnen clean.id , som er påkrævet for din tilgang, når MERGE bruger dual som kilde for hver række.

Dette er mindre sandsynligt, mens du siger id er en primær nøgle .

dybest set du gør det rigtige, og du vil se udførelsesplan ligner den nedenfor:

--------------------------------------------------------------------------------------------------- | 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å udførelsesplanen er fin og fungerer effektivt, men den har et problem.

Husk du altid bruger et indeks, du vil være glad, mens du behandler få rækker, men det vil ikke skalere .

Hvis du behandler en millioner af poster, kan du falde tilbage til en totrinsbehandling,

  • indsæt alle rækker i en midlertidig tabel

  • udføre en enkelt MERGE sætning ved hjælp af den midlertidige tabel

Den store fordel er, at Oracle kan åbne en hash join og slippe af med indeksadgangen for hver af millionerne rækker.

Her et eksempel på en test af clean tabel initieret med 1M id (ikke vist) og udfører 1M insert og 1M opdateringer:

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)
 

Testen løber i ca. 10 sekunder, hvilket er mindre end halvdelen af ​​dig nærmer dig med MERGE ved hjælp af dual .

Hvis dette stadig ikke er nok, bliver du nødt til at bruge parallel mulighed .



  1. MySql vælg format, rund kolonne

  2. Fix:"Sætningen BACKUP LOG er ikke tilladt, mens gendannelsesmodellen er SIMPLE" i SQL Server (og SQL Edge)

  3. Ekskluder en kolonne ved hjælp af SELECT * [undtagen kolonneA] FRA tabelA?

  4. Indtastningstype tekstfelt giver rettet fejl 2147483647