在 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 分钟。看看你的情况是否可以接受。