Ако искате масивна проблеми с вашия подход, много вероятно ви липсва индекс в колоната clean.id
, което се изисква за вашия подход, когато MERGE
използва dual
като източник за всеки ред.
Това е по-малко вероятно, докато казвате id
е първичен ключ .
И така основно мислите правилно и ще видите план за изпълнение подобен на този по-долу:
---------------------------------------------------------------------------------------------------
| 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)
Така че планът за изпълнение е добър и работи ефективно, но има един проблем.
Не забравяйте, че винаги използвате индекс, ще бъдете щастливи, докато обработвате няколко реда, но той няма да се мащабира .
Ако обработвате милиони от записи, можете да се върнете към обработка в две стъпки,
-
вмъкнете всички редове във временна таблица
-
извършете едно
MERGE
израз с помощта на временната таблица
Голямото предимство е, че Oracle може да отвори hash join
и се отървете от достъпа до индекса за всеки от милиона редове.
Ето един пример за тест на clean
таблица, инициирана с 1M id
(не е показано) и извършване на 1M вмъкване и 1M актуализации:
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)
Тестът се изпълнява за прибл. 10 секунди, което е по-малко от половината ви приближаване с MERGE
използвайки dual
.
Ако това все още не е достатъчно, ще трябва да използвате паралелна опция .