加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Oracle高效插入大量数据

发布时间:2020-12-12 14:41:09 所属栏目:百科 来源:网络整理
导读:需求:数据迁移,从远端数据库查询数据写入到生产库中。 遇到问题,数据量为千万级别(具体是6千多万条记录的数据),直接使用insert into 目标表 select * from 数据源表。 因为目标表本身有上千万数据,且有主键和索引,导致写表非常慢。 执行了5,6个小时

需求:数据迁移,从远端数据库查询数据写入到生产库中。

遇到问题,数据量为千万级别(具体是6千多万条记录的数据),直接使用insert into 目标表 select * from 数据源表。

因为目标表本身有上千万数据,且有主键和索引,导致写表非常慢。

执行了5,6个小时还没跑完,第二天看索性plsqldev已经卡死了。

只能强行杀掉了plsqldev的进程。

再看看数据,一条都没写进去,有点崩溃。。。

网上查找了高效插入大量数据的方法,原文地址http://www.cnblogs.com/quanweiru/p/5325635.html

写的很好,很实用。

在测试库测试了下,使用分区表,插入数据到底能快多少。

前提:测试库环境下,表都是没有主键和索引的。

step1,在测试库新建了一个分区表

create table AC83_P
(
  aaz219 NUMBER(16) not null,aaz220 NUMBER(16),aaa027 VARCHAR2(12),aac001 NUMBER(20),aaa036 VARCHAR2(6),aaa038 VARCHAR2(3),aaa085 VARCHAR2(1),aaa088 VARCHAR2(1),aae140 VARCHAR2(6),aae002 NUMBER(6),aae003 NUMBER(6),aae019 NUMBER(16,2),bae134 NUMBER(16,aae013 VARCHAR2(150),baz057 NUMBER(16),baa018 NUMBER(20) not null,bad709 VARCHAR2(20),bae023 VARCHAR2(9),bad305 VARCHAR2(20)
) partition by hash(aaz219)(
  partition part01 tablespace data01,partition part02 tablespace data01,partition part03 tablespace data01,partition part04 tablespace data01,partition part05 tablespace data01,partition part06 tablespace data01,partition part07 tablespace data01,partition part08 tablespace data01
);

step2,将表 ac83 (66,325,831条记录)写入到分区表。

alter table ac83 nologging;
insert /*+ append */ into ac83_p select * from ac83;--2分钟
alter table ac83 logging;
commit;

结果吓了我一跳,这也 太!快!了! 吧!。2分钟,更准确是116秒完成了整个写入。

顿时有种喜极而泣的感觉。似乎看到了胜利的曙光

ps: +append 只适用于 串行的情况,并行会产生enqueue。

--=========实验结果很好!===========

==>>但问题来了:

1)迁移到目标库, 目标库的表本身有记录,且有主键和索引,都不能删的。

2)目标库的表不是分区表。

==>>新思路:

根据博文提示,可以适用并的方式写入。数据源表 做分区。对每个分区分别insert到目标库。

然而,执行分区写入的时候,报错了

SELECT 
*
FROM AC83_p@dblink_zhdata partition(part01);

ORA-14100: 分区扩展表名不能指远程对象

分析出错原因: 原文地址http://blog.csdn.net/annicybc/article/details/852561

测试发现虽然通过建立远端对象同义词的方式可以使用PARTITION语句,但是PARTITION语句并没有起任何作用。而且在最后的查询中,指定了一个不存在的分区,但是并没有报错,说明Oracle忽略了PARTITION语句。

说明oracle还是不能通过数据库链进行PARTITION相关的操作,但是如果对同义词采用这种方式的查询,则Oracle没有进行相应的判断,而仅仅是忽略分区语句。

很遗憾,不能通过数据源表 改为分区表,分别insert的办法进行并行写入到目标库。

--============方法2:将分区表按分区拆成几个普通表,并行写入到目标库=======

step1,按分区进行拆分表,新建分表

create table ac83_p1 as SELECT * FROM ac83_p partition(part01);
create table ac83_p2 as SELECT * FROM ac83_p partition(part02);
create table ac83_p3 as SELECT * FROM ac83_p partition(part03);
create table ac83_p4 as SELECT * FROM ac83_p partition(part04);
create table ac83_p5 as SELECT * FROM ac83_p partition(part05);
create table ac83_p6 as SELECT * FROM ac83_p partition(part06);
create table ac83_p7 as SELECT * FROM ac83_p partition(part07);
create table ac83_p8 as SELECT * FROM ac83_p partition(part08);

6千多万数据,分配到8张表中,每个表有8百多万记录。

step2,尝试单独写入一个分表。

alter table ac83 nologging;
INSERT /*+ append */ INTO  AC83 
SELECT 
*
FROM AC83_p1@dblink_zhdata;
commit;
alter table ac83 logging;

8百多万的数据,看需要多上时间,在写入表有主键和索引的情况下,从远端写入需要多长时间。

13分钟过去了,还没insert完。预估它需要1个小时。静待结果

执行完了, 结果是 1488 s,约24分钟。比预估的还好。

但并行insert同一个表时,不能用/*+ append*/,会产生enqueue。

执行剩下的 7个分表

写入过程中,提示空间不足了。

增加了表空间,写入前为 31G

--insert 前
SELECT a.tablespace_name,sum(bytes)/1024/1024 FROM dba_free_space a WHERE a.tablespace_name in ('GDYLSY_INDEX','GDYLSY_DATA') group by a.tablespace_name;
SELECT 34352398336/1024/1024/1024 FROM dual;--31G
GDYLSY_INDEX;--2554.56mb
GDYLSY_DATA;--32069.56mb--31.31G

测试下 6千万条记录,占用表空间大概多少?

insert 完成查看剩余表空间

GDYLSY_DATA;--26949.56mb--26.31G

GDYLSY_INDEX;--604.125mb

--索引花掉 1950mb --1.9G

--数据记录花掉 5120mb --5G

6千万的数据,占用的空间大致是6-7G。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读