Jika Anda ingin memiliki besar masalah dengan pendekatan Anda, Anda sangat mungkin kehilangan indeks pada kolom clean.id
, yang diperlukan untuk pendekatan Anda saat MERGE
menggunakan dual
sebagai sumber untuk setiap baris.
Ini lebih kecil kemungkinannya saat Anda mengatakan id
adalah kunci utama .
Jadi pada dasarnya Anda melakukan pemikiran yang benar dan Anda akan melihat rencana eksekusi mirip seperti di bawah ini:
---------------------------------------------------------------------------------------------------
| 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)
Jadi rencana pelaksanaannya baik-baik saja dan bekerja secara efektif, tetapi ada satu masalah.
Ingat selalu Anda menggunakan indeks, Anda akan senang saat memproses beberapa baris, tetapi tidak akan menskala .
Jika Anda memproses jutaan catatan, Anda mungkin kembali ke pemrosesan dua langkah,
-
menyisipkan semua baris dalam tabel sementara
-
melakukan satu
MERGE
pernyataan menggunakan tabel sementara
Keuntungan besar adalah bahwa Oracle dapat membuka hash join
dan singkirkan akses indeks untuk setiap juta baris.
Berikut contoh pengujian clean
tabel dimulai dengan 1 juta id
(tidak ditampilkan) dan melakukan penyisipan 1 juta dan pembaruan 1 juta:
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)
Tes berjalan dalam kira-kira. 10 detik, yang kurang dari setengah dari Anda mendekati dengan MERGE
menggunakan dual
.
Jika ini masih belum cukup, Anda harus menggunakan opsi paralel .