我們來比較一下下列SQL插入大量數據時的速度對比。
動態寫法->靜態寫法->批量插入寫法->集合寫法
1.
sqlplus scott/tiger
create table t(x int);
--將共享池清空
alter system flush shared_pool;
編寫一個簡單的存儲過程,實現將1到10萬的值插入t表的需求。
create or replace procedure proc1
as
begin
for i in 1..100000
loop
execute immediate
'insert into values('||i||')';
commit;
end loop;
end;
/
接下來
drop table t purge;
create table t(x int);
alter system flush shared_pool;
SCOTT@ PROD>set timing on
SCOTT@ PROD>exec proc1;
PL/SQL procedure successfully completed.
Elapsed: 00:00:46.30
SCOTT@ PROD>select count(*) from t;
COUNT(*)
----------
100000
2.利用綁定變量實現再次加速
SCOTT@ PROD>create or replace procedure proc2
2 as
3 begin
4 for i in 1..100000
5 loop
6 execute immediate
7 'insert into t values(:x)'using i;
8 commit;
9 end loop;
10 end;
11 /
接下來
SCOTT@ PROD>drop table t purge;
SCOTT@ PROD>create table t(x int);
SYS@ PROD>alter system flush shared_pool;
SCOTT@ PROD>exec proc2;
PL/SQL procedure successfully completed.
Elapsed: 00:00:10.97
SCOTT@ PROD>select count(*) from t;
COUNT(*)
----------
100000
對比時間加速了不少,這是因為第一種在共享池中每次執行插入語句有很多,而SQL_ID各自不同,每個語句都只是解析1次,執行1次解析了10萬次,而第二種加了綁定變量,10萬條語句可以被HASH成一個SQL_ID值,解析1次,執行10萬次,所以速度也就加快了。
注:細心的人會發想為什么會用到execute immediate,這是一種動態的SQL語句寫法,常用於表名字段名是變量,入參的情況,由於表名都不知道,所以當讓不能直接寫SQL語句了,所以要靠動態SQL語句根據傳入的表名參數,來拼成一條SQL語句,由execute immediate調用執行,但是這里顯然是多此一舉,直接insert into t values(i)完全可以,因為表名就是t.接下來然我們看看直接用后者的情況。
3.
create or replace procedure proc3
as
begin
for i in 1..100000
loop
insert into t values(i);
commit;
end loop;
end;
/
--這里要記得先預先執行一遍,將過程創建起來!
接下來:
drop table t purge;
create table t(x int);
alter system flush shared_pool;
set timing on
exec proc3;
Elapsed: 00:00:06.25
原因proc3也是實現了綁定變量,而動態SQL的特點是執行過程中再解析,而靜態SQL的特點是編譯的過程就解析好了。這也是提升速度的原因。
4.批量提交,再次加速(注意看commit與上面commit位置的不同)
create or replace procedure proc4
as
begin
for i in 1..100000
loop
insert into t values(i);
end loop;
commit;
end;
/
接下來:
drop table t purge;
create table t(x int);
set timing on
SCOTT@ PROD>exec proc4;
PL/SQL procedure successfully completed.
Elapsed: 00:00:01.69
5.集合的寫法,飛躍的提速
drop table purge;
create table t(x int);
alter system flush shared_pool;
set timing on
insert into t select rownum from dual connect by level<=100000;
99999 rows created.
Elapsed: 00:00:00.09
6.直接路徑方法加速
drop table t purge;
alter system flush shared_pool;
set timing on
create table t as select rownum x from dual connect by level<=10000000;
用時:00:00:10.14(這里我有改為添加1000萬數據)
這里真正原因是insert into t select 的方式是將數據先寫到data buffer中,然后再刷到磁盤中,而create table t 的方式卻是跳過了數據緩沖區,直接寫進磁盤中,這種方式又稱直接路徑讀寫方式,因為原本是數據先到內存,再到磁盤,更改為直接到磁盤,少了個步驟,因而速度提升了許多。
直接路徑讀寫方式的缺點在於由於數據不經過數據緩沖區,所以在數據緩沖區中一定讀不到這些數據,因此一定會有物理讀,但是在很多時候,尤其是在海量數據需要遷移插入時,快速插入才是真正的第一目的,該表一般記錄巨大,data buffer 甚至還裝不下其十分之一,百分之一,這些共享內存的數據意義不大,這是我們一般會選擇直接路徑讀寫方式來完成海量數據的插入。
7.並行設置,無敵加速
drop table t purge;
alter system flush shared_pool;
set timing on
create table t nologging parallel 64 as select rownum x from dual connect by level<=10000000;
不過並行最大的特點就是占用了大多數CPU的資源,如果是一個並發環境,很多應用在跑,因為這個影響課別的應用,導致別的應用資源不足,將引起很多嚴重問題,所以要三思后行,連接清除該機器是否允許你這樣占用全部的資源。
