----
Compare the performance of single INSERT vs array BULK INSERT.
Result
------
After you run benchmark a few more times, you will get about same result as I saw.
Bulk DML spend 20% more CPU time,
Latches are about same. No big difference.
db block gets, physical reads, consistent gets, session logical reads are all about same.
Bulk DML take 2MB more session pga memory is expected, to cache association array (1200 bytes * 1000 rows) in shared_pool memory. no big deal.
Conclusion
-----------
Consider single SQL first.
Only when the data process logic is too complicated, we may go with Bulk DML, there will be a little performance impact, e.g. 20% more CPU used.
Notes: Thanks for Tom Kyte pointing out the design strategy.
(http://mujiang.blogspot.com/2011/06/question-to-asktom-in-oracle-magazine.html)
Reference
---------
Oracle® Database PL/SQL Language Reference
11g Release 1 (11.1)
12 Tuning PL/SQL Applications for Performance
Reducing Loop Overhead for DML Statements and Queries with Bulk SQL.
* Running One DML Statement Multiple Times (FORALL Statement)
* Retrieving Query Results into Collections (BULK COLLECT Clause)
Setup
-----
drop table listing_wide purge;
create table listing_wide
(
vendor_id number(10,0) Not Null ,
listing_id number(20,0) Not Null ,
match_col varchar2(1) Not Null ,
vendor_listing_id VarChar2(40) Not Null ,
hash_lite varchar2(32) ,
hash_code VarChar2(32) ,
qty number(5,0) Not Null ,
price number(10,2) Not Null ,
create_date Date default sysdate Not Null ,
update_date Date default sysdate Not Null ,
bsa_vend Varchar2(30) ,
isbn_raw Varchar2(25) ,
subject Varchar2(2000) ,
author varchar2(750) ,
title varchar2(750) ,
vend_catalog varchar2(255) ,
description varchar2(4000)
)
NOLOGGING
PARTITION BY LIST (vendor_id)
(
PARTITION v2134736 values( 2134736 ),
PARTITION v8408184 values( 8408184 ),
PARTITION v1 values( 1 ),
PARTITION v2 values( 2 ),
PARTITION vendor_NULL VALUES (NULL),
PARTITION vendor_small VALUES (DEFAULT)
)
NOCOMPRESS
NOPARALLEL
ENABLE ROW MOVEMENT;
drop table listing_purge;
create table listing_purge
NOLOGGING
PARTITION BY LIST (vendor_id)
(
PARTITION v2134736 values( 2134736 ),
PARTITION v8408184 values( 8408184 ),
PARTITION v1 values( 1 ),
PARTITION v2 values( 2 ),
PARTITION vendor_NULL VALUES (NULL),
PARTITION vendor_small VALUES (DEFAULT)
)
as
select a.*
from listing_wide a
where 1=0;
alter table listing_purge modify (
create_date Date default sysdate ,
update_date Date default sysdate
);
Test
----
truncate table listing_wide;
truncate table listing_purge;
insert /*+ append */ into listing_purge
(listing_id, vendor_id, price, qty,hash_lite, hash_code, vendor_listing_id, author, title,subject,isbn_raw, bsa_vend
,match_col)
select
rownum listing_id,
mod(rownum,2) + 1 vendor_id,
1.11 price,
10 qty,
rpad('x',31,'x') hash_lite,
rpad('x',31,'x') hash_code,
rownum vendor_listing_id,
rpad(rownum,400,'x') author,
rpad('x',400,'x') title,
rpad('x',300,'x') subject,
rownum isbn_raw,
mod(rownum,100)||','||mod(Round(rownum/10),100) bsa_vend
,'x' match_col
from dual
connect by level <= 80100;
commit;
set serveroutput on
set linesize 200
begin
tmp_benchmark;
end;
/
select vendor_id, count(*) from listing_wide
group by vendor_id;
select vendor_id, count(*) from listing_purge
group by vendor_id;
Code
----
CREATE OR REPLACE procedure tmp_benchmark
as
l_cnt number := 0; l_upd_rows number := 0;
l_fetch_limit PLS_INTEGER := 1000;
cursor c2 is
select listing_id, vendor_id, price, qty,hash_lite, hash_code, vendor_listing_id, author, title,subject,isbn_raw, bsa_vend, match_col
from listing_purge partition (v2);
TYPE listing_purge_tab is table of c2%rowtype;
lt_book listing_purge_tab;
BEGIN
runStats_pkg.rs_start;
INSERT INTO listing_wide
(listing_id, vendor_id, price, qty,hash_lite, hash_code, vendor_listing_id, author, title,subject,isbn_raw, bsa_vend, match_col)
select listing_id, vendor_id, price, qty,hash_lite, hash_code, vendor_listing_id, author, title,subject,isbn_raw, bsa_vend, match_col
from listing_purge partition (v1);
commit;
runStats_pkg.rs_middle;
-- Open cursor
OPEN c2;
LOOP
fetch c2 BULK COLLECT INTO lt_book LIMIT l_fetch_limit;
FORALL j IN lt_book.FIRST..lt_book.LAST
INSERT into listing_wide
(listing_id, vendor_id, price, qty,hash_lite, hash_code, vendor_listing_id, author, title,subject,isbn_raw, bsa_vend, match_col)
values (lt_book(j).listing_id, lt_book(j).vendor_id, lt_book(j).price, lt_book(j).qty, lt_book(j).hash_lite, lt_book(j).hash_code,
lt_book(j).vendor_listing_id, lt_book(j).author, lt_book(j).title, lt_book(j).subject, lt_book(j).isbn_raw, lt_book(j).bsa_vend
, lt_book(j).match_col)
;
l_upd_rows := l_upd_rows + SQL%RowCount;
exit when lt_book.COUNT < l_fetch_limit;
--exit when c2%notfound;
END LOOP;
close c2;
commit;
runStats_pkg.rs_stop;
EXCEPTION
WHEN others THEN
--u$err.err;
raise;
END;
/
RunStats
--------
Run1 ran in 669 hsecs
Run2 ran in 914 hsecs
run 1 ran in 73.19% of the time
Name Run1 Run2 Diff
STAT...parse count (hard) 2 3 1
LATCH.DML lock allocation 328 327 -1
STAT...sorts (memory) 1 0 -1
STAT...parse time cpu 2 0 -2
LATCH.internal temp table obje 4 2 -2
LATCH.shared pool simulator 6 8 2
LATCH.ASM db client latch 4 6 2
STAT...enqueue releases 1,222 1,224 2
LATCH.space background task la 7 5 -2
STAT...redo log space requests 0 2 2
STAT...Heap Segment Array Upda 146 148 2
STAT...Heap Segment Array Inse 12 14 2
STAT...HSC Heap Segment Block 50,222 50,224 2
STAT...index scans kdiixs1 98 96 -2
STAT...enqueue requests 1,220 1,224 4
STAT...application wait time 0 4 4
STAT...physical read total mul 153 148 -5
STAT...redo ordering marks 1,121 1,126 5
STAT...messages sent 97 105 8
STAT...session logical reads 147,017 147,029 12
STAT...commit cleanouts 3,364 3,376 12
STAT...consistent changes 24 38 14
STAT...db block changes 154,297 154,313 16
LATCH.Consistent RBA 96 80 -16
STAT...parse time elapsed 67 51 -16
LATCH.lgwr LWN SCN 97 78 -19
STAT...redo entries 102,505 102,524 19
STAT...redo buffer allocation 0 22 22
LATCH.post/wait queue 1 31 30
STAT...recursive cpu usage 91 121 30
STAT...redo log space wait tim 0 30 30
STAT...CPU used by this sessio 91 125 34
LATCH.session allocation 7,536 7,574 38
LATCH.In memory undo latch 9 48 39
STAT...physical read total IO 275 235 -40
LATCH.row cache objects 2,688 2,642 -46
STAT...execute count 261 310 49
STAT...consistent gets 19,683 19,632 -51
LATCH.shared pool 138 196 58
STAT...db block gets 127,334 127,397 63
LATCH.undo global data 8,608 8,537 -71
STAT...active txn count during 8,180 8,107 -73
STAT...recursive calls 3,858 3,941 83
LATCH.enqueues 2,034 2,132 98
STAT...user I/O wait time 564 670 106
LATCH.enqueue hash chains 2,525 2,634 109
STAT...table scan rows gotten 50,445 50,315 -130
LATCH.MinActiveScn Latch 16,931 16,796 -135
LATCH.redo allocation 295 467 172
STAT...physical reads 10,010 10,194 184
STAT...Number of read IOs issu 0 184 184
LATCH.cache table scan latch 231 19 -212
STAT...Elapsed Time 669 920 251
STAT...undo change vector size 3,185,292 3,185,592 300
LATCH.redo writing 295 709 414
LATCH.multiblock read objects 464 38 -426
LATCH.object queue header heap 3 451 448
LATCH.active checkpoint queue 2 457 455
LATCH.messages 368 1,250 882
LATCH.cache buffer handles 15,010 13,714 -1,296
STAT...free buffer inspected 10,054 11,522 1,468
LATCH.cache buffers lru chain 20,881 22,578 1,697
LATCH.simulator hash latch 13,132 10,817 -2,315
STAT...hot buffers moved to he 560 3,105 2,545
STAT...IMU Redo allocation siz 8,236 11,044 2,808
STAT...dirty buffers inspected 1 4,860 4,859
LATCH.checkpoint queue latch 201 7,974 7,773
LATCH.cache buffers chains 545,026 536,670 -8,356
LATCH.object queue header oper 34,953 44,292 9,339
STAT...physical reads cache pr 9,735 133 -9,602
STAT...free buffer requested 20,720 10,987 -9,733
STAT...consistent gets from ca 10,729 959 -9,770
STAT...physical reads cache 10,010 184 -9,826
STAT...physical reads direct 0 10,010 10,010
STAT...consistent gets direct 0 10,010 10,010
STAT...consistent gets from ca 19,683 9,622 -10,061
STAT...redo size 78,097,020 78,123,668 26,648
STAT...IMU undo allocation siz 52,228 908 -51,320
STAT...physical read total byt 82,001,920 83,509,248 1,507,328
STAT...physical IO disk bytes 82,001,920 83,509,248 1,507,328
STAT...cell physical IO interc 82,001,920 83,509,248 1,507,328
STAT...physical read bytes 82,001,920 83,509,248 1,507,328
STAT...session pga memory 0 2,162,688 2,162,688
STAT...Effective IO time 0 6,195,022 6,195,022
Run1 latches total versus runs -- difference and pct
Run1 Run2 Diff Pct
672,749 681,506 8,757 98.72%
PL/SQL procedure successfully completed.