-
Notifications
You must be signed in to change notification settings - Fork 849
/
Copy pathforall-inserts-comparison.sql
216 lines (159 loc) · 4.61 KB
/
forall-inserts-comparison.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/*
Sure, we say FORALL is fast, but how fast, really? And how does it compare
to "pure" SQL (which of course you should use whenever possible!)?
*/
CREATE TABLE parts (partnum NUMBER, partname VARCHAR2 (15));
CREATE TABLE parts2 (partnum NUMBER, partname VARCHAR2 (15));
CREATE OR REPLACE TYPE parts_ot IS OBJECT
(partnum NUMBER, partname VARCHAR2 (15))
/
CREATE OR REPLACE TYPE partstab IS TABLE OF parts_ot;
/
CREATE OR REPLACE PROCEDURE compare_inserting (num IN INTEGER)
IS
TYPE numtab IS TABLE OF parts.partnum%TYPE;
TYPE nametab IS TABLE OF parts.partname%TYPE;
TYPE parts_t is table of parts%ROWTYPE index by pls_integer;
parts_tab parts_t;
pnums numtab := numtab ();
pnames nametab := nametab ();
parts_nt partstab := partstab ();
l_start INTEGER;
PROCEDURE start_timer
IS
BEGIN
l_start := DBMS_UTILITY.GET_CPU_TIME;
END start_timer;
PROCEDURE show_elapsed_time ( message_in IN VARCHAR2 )
IS
BEGIN
DBMS_OUTPUT.put_line (
CASE
WHEN message_in IS NULL THEN 'Completed in:'
ELSE '"' || message_in || '" completed in: '
END
|| (DBMS_UTILITY.GET_CPU_TIME - l_start)
|| ' cs');
/* Reset timer */
start_timer;
END show_elapsed_time;
BEGIN
pnums.EXTEND (num);
pnames.EXTEND (num);
parts_nt.EXTEND (num);
FOR indx IN 1 .. num
LOOP
pnums (indx) := indx;
pnames (indx) := 'Part ' || TO_CHAR (indx);
parts_nt (indx) := parts_ot (NULL, NULL);
parts_nt (indx).partnum := indx;
parts_nt (indx).partname := pnames (indx);
END LOOP;
start_timer;
FOR indx IN 1 .. num
LOOP
INSERT INTO parts
VALUES (pnums (indx), pnames (indx) );
END LOOP;
show_elapsed_time ('FOR loop (row by row)' || num);
ROLLBACK;
start_timer;
FORALL indx IN 1 .. num
INSERT INTO parts
VALUES (pnums (indx), pnames (indx)
);
show_elapsed_time ('FORALL (bulk)' || num);
ROLLBACK;
start_timer;
INSERT INTO parts
SELECT *
FROM TABLE (parts_nt);
show_elapsed_time ('Insert Select from nested table ' || num);
ROLLBACK;
start_timer;
INSERT /*+ APPEND */
INTO parts
SELECT *
FROM TABLE (parts_nt);
show_elapsed_time ('Insert Select WITH DIRECT PATH ' || num);
ROLLBACK;
EXECUTE IMMEDIATE 'TRUNCATE TABLE parts';
/* Load up the table. */
FOR indx IN 1 .. num
LOOP
INSERT INTO parts
VALUES (indx, 'Part ' || TO_CHAR (indx)
);
END LOOP;
COMMIT;
start_timer;
INSERT INTO parts2
SELECT *
FROM parts;
show_elapsed_time ('Insert Select 100% SQL');
EXECUTE IMMEDIATE 'TRUNCATE TABLE parts2';
start_timer;
SELECT *
BULK COLLECT
INTO parts_tab
FROM parts;
FORALL indx IN parts_tab.FIRST .. parts_tab.LAST
INSERT INTO parts2
VALUES parts_tab (indx);
show_elapsed_time ('BULK COLLECT - FORALL');
ROLLBACK;
END;
/
BEGIN
compare_inserting (100000);
END;
/
-- With Associative Arrays
-- A visitor wondered if nested tables were faster than associative arrays. Let's find out!
DECLARE
PROCEDURE compare_inserting (num IN INTEGER)
IS
TYPE numtab IS TABLE OF parts.partnum%TYPE index by pls_integer;
TYPE nametab IS TABLE OF parts.partname%TYPE index by pls_integer;
TYPE parts_t is table of parts%ROWTYPE index by pls_integer;
parts_tab parts_t;
pnums numtab;
pnames nametab ;
parts_nt partstab ;
l_start INTEGER;
PROCEDURE start_timer
IS
BEGIN
l_start := DBMS_UTILITY.GET_CPU_TIME;
END start_timer;
PROCEDURE show_elapsed_time ( message_in IN VARCHAR2 )
IS
BEGIN
DBMS_OUTPUT.put_line (
CASE
WHEN message_in IS NULL THEN 'Completed in:'
ELSE '"' || message_in || '" completed in: '
END
|| (DBMS_UTILITY.GET_CPU_TIME - l_start)
|| ' cs');
/* Reset timer */
start_timer;
END show_elapsed_time;
BEGIN
FOR indx IN 1 .. num
LOOP
pnums (indx) := indx;
pnames (indx) := 'Part ' || TO_CHAR (indx);
END LOOP;
start_timer;
FORALL indx IN 1 .. num
INSERT INTO parts
VALUES (pnums (indx), pnames (indx)
);
show_elapsed_time ('FORALL with associative arrays' || num);
ROLLBACK;
END;
BEGIN
compare_inserting (100000);
END;
/