... We have not special situation but have hired oracle consultant and what he suggest is to use bulk insert instead of single sql. ...
why? do they want it to take longer?
... so he suggested us to use bulk insert which i think will be slower. ...
you sir, are correct. But you know what, you should ask this expert to SHOW YOU the numbers, not the other way around. They should PROVE TO YOU that what they say is correct.
In your test, I would surmise that run two ran faster only because run1 did the work of getting all of the blocks into the buffer cache - as evidenced by the reduced IO's - run the test the other way and see what you see then :)
writing code to replace that single insert would be *not smart*, as in *not intelligent*, as in *the wrong way*
I hope you do know that:
...
INSERT /*+ append */ INTO t2 VALUES l_data(i);
.....
is identical to
INSERT INTO t2 VALUES l_data(i);
(except in 11gR1 where append actually does 'work' by accident, fixed in 11gr2). Direct path loads for single row inserts would be deadly - they do not happen fortunately.
also, the indentation of your 'commit' makes me think you think it is "in" the forall loop - it is not. It is after - the forall is not really a loop - it is a single statement.
Let's do your test - removing the complex query and just loading data (so we are comparing "loading to loading" and not the performance of the query loading from from execution to execution.
ops$tkyte%ORA10GR2> drop table t1;
Table dropped.
ops$tkyte%ORA10GR2> drop table t2;
Table dropped.
ops$tkyte%ORA10GR2> create table t1 as select owner, object_name, object_id from all_objects where 1=0;
Table created.
ops$tkyte%ORA10GR2> create table t2 as select owner, object_name, object_id from all_objects where 1=0;
Table created.
ops$tkyte%ORA10GR2> exec runstats_pkg.rs_start;
PL/SQL procedure successfully completed.
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> begin
2 for i in 1 .. 10
3 loop
4 insert /*+ append */ into t1 select owner,object_name, object_id from all_objects;
5 commit;
6 end loop;
7 end;
8 /
PL/SQL procedure successfully completed.
ops$tkyte%ORA10GR2> exec runstats_pkg.rs_middle;
PL/SQL procedure successfully completed.
ops$tkyte%ORA10GR2> declare
2 TYPE ARRAY IS TABLE OF t2%ROWTYPE;
3 l_data ARRAY;
4 CURSOR c IS select owner,object_name, object_id from all_objects;
5 BEGIN
6 for i in 1 .. 10
7 loop
8 OPEN c;
9 LOOP
10 FETCH c BULK COLLECT INTO l_data LIMIT 10000;
11 FORALL i IN 1..l_data.COUNT
12 INSERT INTO t2 VALUES l_data(i);
13 commit;
14 EXIT WHEN c%NOTFOUND;
15 END LOOP;
16 CLOSE c;
17 end loop;
18 end;
19 /
PL/SQL procedure successfully completed.
ops$tkyte%ORA10GR2> exec runstats_pkg.rs_stop();
Run1 ran in 1835 cpu hsecs
Run2 ran in 3624 cpu hsecs
run 1 ran in 50.63% of the time
Name Run1 Run2 Diff
...
LATCH.session allocation 104,502 105,622 1,120
LATCH.enqueues 532 1,758 1,226<b>
STAT...DB time 1,909 3,634 1,725
STAT...Elapsed Time 1,906 3,635 1,729
STAT...recursive cpu usage 1,838 3,618 1,780
STAT...CPU used when call star 1,841 3,627 1,786
STAT...CPU used by this sessio 1,838 3,627 1,789</b>
STAT...active txn count during 4 2,109 2,105
STAT...cleanout - number of kt 4 2,110 2,106
STAT...consistent gets - exami 202,590 204,708 2,118
LATCH.undo global data 306 2,813 2,507
STAT...calls to kcmgcs 41 2,770 2,729
STAT...db block gets direct 2,740 0 -2,740
STAT...physical writes direct 2,740 0 -2,740
STAT...physical writes non che 2,740 0 -2,740
STAT...physical writes 2,740 0 -2,740
STAT...commit cleanouts succes 96 2,878 2,782
STAT...commit cleanouts 100 2,883 2,783
STAT...free buffer requested 147 3,067 2,920
STAT...redo subscn max counts 59 2,985 2,926
STAT...calls to get snapshot s 115,094 118,047 2,953
LATCH.cache buffer handles 2,860 6,568 3,708
STAT...table scan rows gotten 1,101,167 1,104,931 3,764
LATCH.object queue header oper 155 6,284 6,129
LATCH.SQL memory manager latch 20 11,379 11,359
STAT...redo entries 1,191 16,061 14,870
STAT...db block changes 1,579 21,969 20,390
STAT...db block gets 4,520 26,343 21,823
STAT...db block gets from cach 1,780 26,343 24,563
STAT...physical read bytes 40,960 16,384 -24,576
STAT...IMU undo allocation siz 2,544 44,452 41,908
LATCH.row cache objects 241,283 308,810 67,527
STAT...IMU Redo allocation siz 320 523,212 522,892
LATCH.simulator hash latch 85,225 702,283 617,058
LATCH.SQL memory manager worka 1,804 786,059 784,255
STAT...physical read total byt 860,160 16,384 -843,776
STAT...undo change vector size 44,512 1,381,504 1,336,992
STAT...buffer is pinned count 729,915 4,218,843 3,488,928
STAT...index scans kdiixs1 651,953 4,140,973 3,489,020
STAT...no work - consistent re 1,242,934 4,779,892 3,536,958
STAT...consistent gets from ca 1,447,391 4,989,399 3,542,008
STAT...consistent gets 1,447,391 4,989,399 3,542,008
STAT...session logical reads 1,451,911 5,015,742 3,563,831
LATCH.cache buffers chains 2,698,761 9,865,284 7,166,523
STAT...physical write bytes 22,446,080 0 -22,446,080
STAT...physical write total by 22,446,080 0 -22,446,080<b>
STAT...redo size 176,692 23,781,996 23,605,304</b>
Run1 latches total versus runs -- difference and pct
Run1 Run2 Diff Pct<b>
3,570,177 12,234,835 8,664,658 29.18%
</b>
PL/SQL procedure successfully completed.
I use cpu hsecs now (replace dbms_utility.get_time with get_CPU_time in runstats)
but as you can see - it takes longer and uses more resources.
YOU CANNOT GET MORE "BULK LOAD" THAN A SINGLE SQL STATEMENT - INSERT INTO SELECT IS THE ULTIMATE BULK LOAD - YOU CANNOT WRITE BULKIER CODE YOURSELF, NO WAY NO HOW.
so, if the consultant believes bulk loading is good (it is), then they went the WRONG DIRECTION didn't they?