Nếu bạn muốn có một đồ sộ vấn đề với cách tiếp cận của bạn, rất có thể bạn đang thiếu chỉ mục trên cột clean.id
, điều đó là bắt buộc đối với phương pháp của bạn khi MERGE
sử dụng dual
làm nguồn cho mỗi hàng.
Điều này ít xảy ra hơn khi bạn đang nói id
là một khóa chính .
Vì vậy, về cơ bản bạn đang suy nghĩ đúng và bạn sẽ thấy kế hoạch thực thi tương tự như bên dưới:
---------------------------------------------------------------------------------------------------
| 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)
Vì vậy, kế hoạch thực thi tốt và hoạt động hiệu quả, nhưng nó có một vấn đề.
Hãy nhớ luôn sử dụng một chỉ mục, bạn sẽ hài lòng khi xử lý một vài hàng, nhưng nó sẽ không chia tỷ lệ .
Nếu bạn đang xử lý một hàng triệu trong số các bản ghi, bạn có thể quay lại xử lý hai bước,
-
chèn tất cả các hàng trong một bảng tạm thời
-
thực hiện một
MERGE
câu lệnh sử dụng bảng tạm thời
Lợi thế lớn là Oracle có thể mở một hash join
không và loại bỏ quyền truy cập chỉ mục cho mỗi triệu hàng.
Dưới đây là một ví dụ về kiểm tra clean
bảng bắt đầu bằng 1 triệu id
(không hiển thị) và thực hiện chèn 1M và cập nhật 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)
Thử nghiệm chạy trong khoảng thời gian. 10 giây, tức là chưa đến một nửa thời gian bạn tiếp cận với MERGE
sử dụng dual
.
Nếu điều này vẫn chưa đủ, bạn sẽ phải sử dụng tùy chọn song song .