比较加快sql语句的大批量插入数据,单车变摩托!

我们来比较一下下列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的资源,如果是一个并发环境,很多应用在跑,因为这个影响课别的应用,导致别的应用资源不足,将引起很多严重问题,所以要三思后行,连接清除该机器是否允许你这样占用全部的资源。

原文地址:https://www.cnblogs.com/wjmbk/p/7967669.html