Skip to content

Commit ce03b28

Browse files
author
Steven Feuerstein
authored
Create forall-inserts-comparison
1 parent 4d0310e commit ce03b28

File tree

1 file changed

+158
-0
lines changed

1 file changed

+158
-0
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/*
2+
Sure, we say FORALL is fast, but how fast, really? And how does it compare to "pure" SQL
3+
(which of course you should use whenever possible!)?
4+
*/
5+
6+
CREATE TABLE parts (partnum NUMBER, partname VARCHAR2 (15))
7+
;
8+
9+
CREATE TABLE parts2 (partnum NUMBER, partname VARCHAR2 (15))
10+
;
11+
12+
CREATE OR REPLACE TYPE parts_ot IS OBJECT
13+
(partnum NUMBER, partname VARCHAR2 (15))
14+
15+
/
16+
17+
CREATE OR REPLACE TYPE partstab IS TABLE OF parts_ot;
18+
19+
/
20+
21+
CREATE OR REPLACE PROCEDURE compare_inserting (num IN INTEGER)
22+
IS
23+
TYPE numtab IS TABLE OF parts.partnum%TYPE;
24+
25+
TYPE nametab IS TABLE OF parts.partname%TYPE;
26+
27+
TYPE parts_t is table of parts%ROWTYPE index by pls_integer;
28+
parts_tab parts_t;
29+
30+
pnums numtab := numtab ();
31+
pnames nametab := nametab ();
32+
parts_nt partstab := partstab ();
33+
34+
/* Timer functionality */
35+
l_start TIMESTAMP;
36+
37+
PROCEDURE start_timer
38+
IS
39+
BEGIN
40+
l_start := SYSTIMESTAMP;
41+
END start_timer;
42+
43+
PROCEDURE show_elapsed_time ( message_in IN VARCHAR2 )
44+
IS
45+
BEGIN
46+
DBMS_OUTPUT.put_line (
47+
CASE
48+
WHEN message_in IS NULL THEN 'Completed in:'
49+
ELSE '"' || message_in || '" completed in: '
50+
END
51+
|| REGEXP_SUBSTR (SYSTIMESTAMP - l_start,
52+
'([1-9][0-9:]*|0)\.\d{3}')
53+
|| ' seconds');
54+
55+
/* Reset timer */
56+
start_timer;
57+
END show_elapsed_time;
58+
BEGIN
59+
pnums.EXTEND (num);
60+
pnames.EXTEND (num);
61+
parts_nt.EXTEND (num);
62+
63+
FOR indx IN 1 .. num
64+
LOOP
65+
pnums (indx) := indx;
66+
pnames (indx) := 'Part ' || TO_CHAR (indx);
67+
parts_nt (indx) := parts_ot (NULL, NULL);
68+
parts_nt (indx).partnum := indx;
69+
parts_nt (indx).partname := pnames (indx);
70+
END LOOP;
71+
72+
start_timer;
73+
74+
FOR indx IN 1 .. num
75+
LOOP
76+
INSERT INTO parts
77+
VALUES (pnums (indx), pnames (indx) );
78+
END LOOP;
79+
80+
show_elapsed_time ('FOR loop (row by row)' || num);
81+
82+
ROLLBACK;
83+
84+
start_timer;
85+
86+
FORALL indx IN 1 .. num
87+
INSERT INTO parts
88+
VALUES (pnums (indx), pnames (indx)
89+
);
90+
91+
show_elapsed_time ('FORALL (bulk)' || num);
92+
93+
ROLLBACK;
94+
95+
start_timer;
96+
97+
INSERT INTO parts
98+
SELECT *
99+
FROM TABLE (parts_nt);
100+
101+
show_elapsed_time ('Insert Select from nested table ' || num);
102+
103+
ROLLBACK;
104+
105+
start_timer;
106+
107+
INSERT /*+ APPEND */
108+
INTO parts
109+
SELECT *
110+
FROM TABLE (parts_nt);
111+
112+
show_elapsed_time ('Insert Select WITH DIRECT PATH ' || num);
113+
114+
ROLLBACK;
115+
116+
EXECUTE IMMEDIATE 'TRUNCATE TABLE parts';
117+
118+
/* Load up the table. */
119+
FOR indx IN 1 .. num
120+
LOOP
121+
INSERT INTO parts
122+
VALUES (indx, 'Part ' || TO_CHAR (indx)
123+
);
124+
END LOOP;
125+
126+
COMMIT;
127+
128+
start_timer;
129+
130+
INSERT INTO parts2
131+
SELECT *
132+
FROM parts;
133+
134+
show_elapsed_time ('Insert Select 100% SQL');
135+
136+
EXECUTE IMMEDIATE 'TRUNCATE TABLE parts2';
137+
138+
start_timer;
139+
140+
SELECT *
141+
BULK COLLECT
142+
INTO parts_tab
143+
FROM parts;
144+
145+
FORALL indx IN parts_tab.FIRST .. parts_tab.LAST
146+
INSERT INTO parts2
147+
VALUES parts_tab (indx);
148+
149+
show_elapsed_time ('BULK COLLECT - FORALL');
150+
END;
151+
152+
/
153+
154+
BEGIN
155+
compare_inserting (100000);
156+
END;
157+
158+
/

0 commit comments

Comments
 (0)