在 oracle 中插入数百万条记录的最佳和最快方法
Best and Fastest way to insert milions records in oracle
我想在oracle中插入500万个唯一的随机数table。每个随机数有 8 位数字。这是我的代码
DECLARE I INT;
J INT;
gen_coupen varchar2(8);
check_coupen varchar2(8);
BEGIN
j :=1;
FOR I IN J..:TO_COUPEN LOOP
select round(dbms_random.value(10000000,99999999),0) into :gen_coupen from dual;
select count(*) into :check_coupen from registration where coupen=:gen_coupen;
if (:check_coupen=0) and LENGTH(:gen_coupen)=8 then
insert into registration (coupen)
values(:gen_coupen);
commit;
end if;
这段代码工作正常,但是插入需要很长时间有没有最快的方法来插入 500 万条记录。
逐行真的很慢。如果可以的话,立刻做;我不能,我没有足够的内存所以我在循环中做,但一次 100 万行。方法如下:
SQL> create table registration (coupen number);
Table created.
SQL> set timing on
SQL> begin
2 for i in 1 .. 5 loop
3 insert into registration (coupen)
4 select round(dbms_random.value(10000000,99999999),0) coupen
5 from dual
6 connect by level <= 1000000;
7 end loop;
8 end;
9 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:17.96
SQL> set timing off
SQL> select count(*) From registration;
COUNT(*)
----------
5000000
SQL>
在我的笔记本电脑和 11g XE 数据库上花费了大约 18 秒。
如果它必须是 500 万个不同的值,则必须对代码进行一些更改。我建议你
- 插入更多行(超过 500 万行)(不要试图在插入阶段避免重复,那么多行会花费太多时间)
- 删除重复项
- 删除多余的行(以便保留 500 万行)
这是一个选项(我包括了计数和时间来显示行数的情况以及需要多少时间)。
create table registration (coupen number);
set serveroutput on
set timing on
declare
l_cnt number;
l_cntdis number;
begin
-- initial insert
dbms_output.put_line('Stage 1: ' || to_char(sysdate, 'hh24:mi:ss'));
for i in 1 .. 5 loop
insert into registration (coupen)
select round(dbms_random.value(10000000,99999999),0) coupen
from dual
connect by level <= 1050000; --> more than 1 million rows per loop iteration (because of duplicates)
end loop;
commit;
select count(*), count(distinct coupen)
into l_cnt, l_cntdis
from registration;
dbms_output.put_line('Stage 2: ' || to_char(sysdate, 'hh24:mi:ss') || ' total = ' || l_cnt ||', distinct = ' || l_cntdis);
execute immediate 'create index i1reg_coup on registration (coupen)';
dbms_output.put_line('Stage 3: ' || to_char(sysdate, 'hh24:mi:ss'));
-- delete remaining duplicates
delete from registration a
where a.rowid > (select min(b.rowid)
from registration b
where b.coupen = a.coupen
);
select count(*), count(distinct coupen)
into l_cnt, l_cntdis
from registration;
dbms_output.put_line('Stage 4: ' || to_char(sysdate, 'hh24:mi:ss') || ' total = ' || l_cnt ||', distinct = ' || l_cntdis);
-- delete superfluous rows (i.e. leave exactly 5.000.000 distinct rows)
delete from registration r
where r.coupen in
(select x.coupen from
(select a.coupen,
row_number() over (order by null) rn
from registration a
) x
where x.rn > 5000000
);
select count(*), count(distinct coupen)
into l_cnt, l_cntdis
from registration;
dbms_output.put_line('Stage 5: ' || to_char(sysdate, 'hh24:mi:ss') || ' total = ' || l_cnt ||', distinct = ' || l_cntdis);
end;
/
结果:
Stage 1: 11:06:49
Stage 2: 11:07:09 total = 5250000, distinct = 5100332
Stage 3: 11:07:18
Stage 4: 11:11:17 total = 5100332, distinct = 5100332
Stage 5: 11:12:02 total = 5000000, distinct = 5000000
PL/SQL procedure successfully completed.
Elapsed: 00:05:13.57
SQL>
在同一台笔记本电脑和 11g XE 上用时略多于 5 分钟。看看你的情况是否可以接受。
我想在oracle中插入500万个唯一的随机数table。每个随机数有 8 位数字。这是我的代码
DECLARE I INT;
J INT;
gen_coupen varchar2(8);
check_coupen varchar2(8);
BEGIN
j :=1;
FOR I IN J..:TO_COUPEN LOOP
select round(dbms_random.value(10000000,99999999),0) into :gen_coupen from dual;
select count(*) into :check_coupen from registration where coupen=:gen_coupen;
if (:check_coupen=0) and LENGTH(:gen_coupen)=8 then
insert into registration (coupen)
values(:gen_coupen);
commit;
end if;
这段代码工作正常,但是插入需要很长时间有没有最快的方法来插入 500 万条记录。
逐行真的很慢。如果可以的话,立刻做;我不能,我没有足够的内存所以我在循环中做,但一次 100 万行。方法如下:
SQL> create table registration (coupen number);
Table created.
SQL> set timing on
SQL> begin
2 for i in 1 .. 5 loop
3 insert into registration (coupen)
4 select round(dbms_random.value(10000000,99999999),0) coupen
5 from dual
6 connect by level <= 1000000;
7 end loop;
8 end;
9 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:17.96
SQL> set timing off
SQL> select count(*) From registration;
COUNT(*)
----------
5000000
SQL>
在我的笔记本电脑和 11g XE 数据库上花费了大约 18 秒。
如果它必须是 500 万个不同的值,则必须对代码进行一些更改。我建议你
- 插入更多行(超过 500 万行)(不要试图在插入阶段避免重复,那么多行会花费太多时间)
- 删除重复项
- 删除多余的行(以便保留 500 万行)
这是一个选项(我包括了计数和时间来显示行数的情况以及需要多少时间)。
create table registration (coupen number);
set serveroutput on
set timing on
declare
l_cnt number;
l_cntdis number;
begin
-- initial insert
dbms_output.put_line('Stage 1: ' || to_char(sysdate, 'hh24:mi:ss'));
for i in 1 .. 5 loop
insert into registration (coupen)
select round(dbms_random.value(10000000,99999999),0) coupen
from dual
connect by level <= 1050000; --> more than 1 million rows per loop iteration (because of duplicates)
end loop;
commit;
select count(*), count(distinct coupen)
into l_cnt, l_cntdis
from registration;
dbms_output.put_line('Stage 2: ' || to_char(sysdate, 'hh24:mi:ss') || ' total = ' || l_cnt ||', distinct = ' || l_cntdis);
execute immediate 'create index i1reg_coup on registration (coupen)';
dbms_output.put_line('Stage 3: ' || to_char(sysdate, 'hh24:mi:ss'));
-- delete remaining duplicates
delete from registration a
where a.rowid > (select min(b.rowid)
from registration b
where b.coupen = a.coupen
);
select count(*), count(distinct coupen)
into l_cnt, l_cntdis
from registration;
dbms_output.put_line('Stage 4: ' || to_char(sysdate, 'hh24:mi:ss') || ' total = ' || l_cnt ||', distinct = ' || l_cntdis);
-- delete superfluous rows (i.e. leave exactly 5.000.000 distinct rows)
delete from registration r
where r.coupen in
(select x.coupen from
(select a.coupen,
row_number() over (order by null) rn
from registration a
) x
where x.rn > 5000000
);
select count(*), count(distinct coupen)
into l_cnt, l_cntdis
from registration;
dbms_output.put_line('Stage 5: ' || to_char(sysdate, 'hh24:mi:ss') || ' total = ' || l_cnt ||', distinct = ' || l_cntdis);
end;
/
结果:
Stage 1: 11:06:49
Stage 2: 11:07:09 total = 5250000, distinct = 5100332
Stage 3: 11:07:18
Stage 4: 11:11:17 total = 5100332, distinct = 5100332
Stage 5: 11:12:02 total = 5000000, distinct = 5000000
PL/SQL procedure successfully completed.
Elapsed: 00:05:13.57
SQL>
在同一台笔记本电脑和 11g XE 上用时略多于 5 分钟。看看你的情况是否可以接受。