如何在5分钟内在pl/sql oracle中插入100万数据?

如何在5分钟内在pl/sql oracle中插入100万数据?,oracle,performance,plsql,Oracle,Performance,Plsql,需要在5分钟内插入大量记录。这是我尝试过的pl/SQL procedure insert_student(name_ in varchar2, address_ in varchar2, phone_ in varchar2, class_ in varchar2) is

需要在5分钟内插入大量记录。这是我尝试过的pl/SQL

procedure insert_student(name_      in varchar2,
                         address_   in varchar2,
                         phone_     in varchar2,
                         class_     in varchar2) is                                  

        begin

          insert into student.student_scholarship(name, address,
          phone, class, date)
          values (name_, address_, phone_, class_, sysdate)
          );
        commit;                
end insert_student; 

对所有语句使用
。它比逐个保存记录或使用
FOR
循环快得多,因为它不会在每次PL/SQL处理器通过SQL语句时更改PL/SQL和SQL之间的上下文

CREATE TABLE students (
    id NUMBER(19,0),
    address VARCHAR2(300)
);
/

CREATE OR REPLACE PACKAGE pack AS
TYPE t_students IS TABLE OF students%ROWTYPE INDEX BY BINARY_INTEGER;

PROCEDURE insert_students( l_students IN t_students);

END pack;
/

CREATE OR REPLACE PACKAGE BODY pack AS

PROCEDURE insert_students( l_students IN t_students) AS
    BEGIN
      FORALL i IN 1..l_students.COUNT
      INSERT INTO students VALUES (l_students(i).id, l_students(i).address);
    END;
END pack;
/

对于下面的模拟,我们已经{A}生成了一个学生表,其中包含1000000行,并填充了随机字符串。由于您没有告诉我们从何处加载数据,我们已{B}将数据导出/卸载到CSV文件,{C}通过外部表使用数据,然后我们将其用于各种插入技术。(全部使用Oracle 12c“开发者日”虚拟机完成)

{A} “源表”

{C} 外桌

create table external_ ( 
  name    varchar2( 4000 )
, address varchar2( 4000 )
, phone   varchar2( 4000 )
, sclass  varchar2( 4000 )
) 
organization external (
  type oracle_loader 
  default directory external_tables
  access parameters 
  ( 
     records field names all files
     fields CSV with embedded record terminators
  ) 
  location 
  (
    'out.csv'
  ) 
)
/
-- quick check
SQL> select count(*) from external_ ;

  COUNT(*)
----------
   1000000
“目的地”表

当使用纯SQL插入1000000行时,我们得到了以下次数(测试运行3次,奖学金表在测试之间被删除)

最糟糕的选择可能是这样的:使用PL/SQL和游标FOR循环(测试运行3次,在测试之间删除)

更好一点:使用PL/SQL的批量操作(同样是3次测试运行的“运行时间”)


很多人都会告诉你:尽可能使用SQL(仅限)。现在,您可能会发现,您最初的方法(使用带参数的过程,一次只执行一次插入)可能不是解决问题的最佳方法。

您尝试过什么吗?你有什么基准测试吗?对于大型数据集,最好使用INSERT作为SELECT或FORALL。(您可以使用APPEND提示提示INSERT)指定您的数据源,因为如果您不这样做,您可能会得到许多不同的和不相关的答案。如果想要获得性能,您需要的是某种批量操作。基本上,PL/SQL将数据存储在RAM中,并将其用作批量插入行的快速方法。看一看,自己尝试一下,并在这里举一个例子。我的朋友对这些东西很好。ol'sqlload是你的百万行插入来自另一个表,一个平面文件,另一个数据库?对您有效的答案将取决于数据源。5分钟内完成100万次应该不会太难。FORALL比单个调用快,但可能比纯SQL
insert into快。。。从…中选择*
。OP没有提供有关其输入数据源的详细信息,因此我们没有理由认为他们需要任何PL/SQL。
set term off
set feed off
set sqlformat csv
spool /home/oracle/data_out/out.csv
select /*+ parallel */* from student ;
spool off
create table external_ ( 
  name    varchar2( 4000 )
, address varchar2( 4000 )
, phone   varchar2( 4000 )
, sclass  varchar2( 4000 )
) 
organization external (
  type oracle_loader 
  default directory external_tables
  access parameters 
  ( 
     records field names all files
     fields CSV with embedded record terminators
  ) 
  location 
  (
    'out.csv'
  ) 
)
/
-- quick check
SQL> select count(*) from external_ ;

  COUNT(*)
----------
   1000000
create table scholarship (
  name    varchar2( 25 )
, address varchar2( 40 )
, phone   varchar2( 20 )
, sclass   varchar2( 5 )
, sdate   date default sysdate
);
-- {1}  SQL: INSERT ... SELECT ...
insert into scholarship ( name, address, phone, sclass ) 
select name, address, phone, sclass from external_ ;

-- 1,000,000 rows inserted.
-- Elapsed: 00:00:02.607
-- Elapsed: 00:00:02.300
-- Elapsed: 00:00:02.473
--{2}  PL/SQL: use a cursor for loop ("slow by slow")
begin
  for rec_ in ( select * from external_ )
  loop
    insert into scholarship ( name, address, phone, sclass )
    values ( rec_.name, rec_.address, rec_.phone, rec_.sclass ) ;
  end loop ;
  commit ;
end ;
/

-- PL/SQL procedure successfully completed.
-- Elapsed: 00:00:24.777
-- Elapsed: 00:00:22.700
-- Elapsed: 00:00:24.291
--{3}  PL/SQL: use BULK COLLECT and FORALL (no need to re-compile in between tests)
create or replace procedure insert_students is
  type student_t is table of external_%rowtype index by pls_integer ;
  lstudents student_t ;
begin
  select * bulk collect into lstudents from external_  ;
  forall i in 1.. lstudents.count
    insert into scholarship ( name, address, phone, sclass )
    values ( lstudents( i ).name, lstudents( i ).address, lstudents( i ).phone, lstudents( i ).sclass  );
end ;
/

begin
  insert_students ;
  commit ;
end ;
/

-- PL/SQL procedure successfully completed.
-- Elapsed: 00:00:08.706
-- Elapsed: 00:00:06.762
-- Elapsed: 00:00:04.989