请教提高上百万行数据insert速度的“经典”方法
有两个结构相同的表table1,table2
将table1插入到table2中:
现在采用两种方法:
1、指定回滚段,回滚段足够大
set transaction use rollback segment RBS1;
INSERT INTO table1 NOLOGGING
SELECT * FROM table2;
commit;
2、采用定义cursor,每5000或10000条记录提交一次
declare
cursor cur_select is
select t1,t2,t3..... from tabl1;
v_id number;
v_t table1%rowtype;
begin
open cur_select;
loop
exit when cur_select%notfound;
fetch cur_select into v_t.t1,v_t.t2,v_t.t3..... ;
insert into table2
(t1,t2,t3......)
values
(v_t.t1,v_t.t2,v_t.t3..... );
v_id := v_id + 1;
if v_id = 10000 then
commit;
v_id := 0;
end if;
end loop;
commit;
end;
我现在只有这两种方法,足够笨的!请教各位高士还有没有其他的方法?
下面是别的一些方法
-----------------------------
改变表的存储策略:
ALTER TABLE aaaa1
PCTFREE 30
PCTUSED 60;
---------这两个值相加要小于100,把PCTFREE搞大,PCTUSED搞小,可能会快一点
2比较可行的方法
insert /*+append*/ into ...nologing
select * from ...
方法二:使用批量拷贝方法
set arraysize 20
set copycommit 5000
copy from username/password@oracle_name append table_name1
using select * from table_name2;
实际效果,方法一要比方法二速度还要快些
alter session set sort_area_size=100000000;
insert into tableb select * from tablea;
commit;
解释(来自网上):
针对每个session,排序首先会使用sort_area_size ,如果不足则会使用临时表空间。
假设sort_area_size = 100k,正好能盛下100条记录进行排序
当排序记录小于等于100条,ok,所有排序在内存中进行,很快
但若超过100条,则会使用临时表空间(利用磁盘进行)
我们选取一个临界值来说明,假设需要排序的记录有10010条
这个时候我们进行的排序会分为101组进行
每读100条进行一次小组排序,然后写入磁盘,第101组只有10条,排序后也写入磁盘
这是进行第二次排序,这次排序将在前100小组里面各抽取一条进行排序。《按照我个人的猜测,应该是排好后每写入一条入磁盘则将该记录所在小组重新抽取一条出来进行排序(这时是有序记录组里面所以很快)》。当这个过程完成后,这时所需要的磁盘空间大约为 实际记录存储空间的2倍(这也是多数书上提到的排序空间大约是记录空间的2倍的原因)
由于还剩下10条记录,于是这10条记录需要跟前面排序的10000条记录进行排序合并,这个代价也是相当大的!
所以,我们通常推荐,假如你需要排序的记录最大为100万条,则sort_area_size最小要能装下1000条,否则如上面的例子,那多余的10条,仅仅10条将会带来巨大的代价!
如果,设置的极度不合理的情况下,排序记录达到了 sort_area_size所能容纳的三次方以上,比如上面例子中排序需要100万记录
那么同样的,重复这个过程,当每一万条记录如上排序后,再如上从这100小组(每组10000条记录)各抽一条进行排序……
在这个过程中,磁盘的消耗和时间的代价大家都应该有个感性认识了
所以,我们建议: sprt_area_size 所能容纳记录数至少大于排序记录数的 平方根