需要在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;
答案 0 :(得分:1)
对于以下模拟,我们{A}生成了一个STUDENT表,其中包含1,000,000行,并填充有随机字符串。由于您没有告诉我们要从何处加载数据,因此我们已经{B}将数据导出/卸载到了CSV文件,{C}通过EXTERNAL表使用了数据,然后利用各种INSERT技术。 (全部使用Oracle 12c“ Developer Days” VM完成)
{A}“源表”
create table student ( name, address, phone, sclass )
as
select
dbms_random.string( 'x', 25 )
, dbms_random.string( 'x', 40 )
, dbms_random.string( 'x', 20 )
, dbms_random.string( 'x', 5 )
from dual
connect by level <= 1000000 ;
-- Elapsed: 00:03:25.032
-- quick check
select count(*) from student ;
COUNT(*)
----------
1000000
{B}将1,000,000行写入CSV文件
set term off
set feed off
set sqlformat csv
spool /home/oracle/data_out/out.csv
select /*+ parallel */* from student ;
spool off
{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
“目的地”表
create table scholarship (
name varchar2( 25 )
, address varchar2( 40 )
, phone varchar2( 20 )
, sclass varchar2( 5 )
, sdate date default sysdate
);
使用纯SQL插入1,000,000行时,我们得到了以下次数(测试运行3次,两次测试之间都删除了SCHOLARSHIP表)。
-- {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
最糟糕的选择可能是:使用PL / SQL和CURSOR FOR LOOP(测试运行3次,两次测试之间都放弃了SCHOLARSHIP)。
--{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
好一点:使用PL / SQL的批量操作(再次进行3次测试的“经过时间”)。
--{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
许多人会告诉您:尽可能使用SQL(仅)。现在,您可能会发现,最初的方法-使用带有参数的过程,并且一次仅执行一次INSERT-可能不是解决问题的最佳方法。
答案 1 :(得分:0)
使用FORALL
语句。它比使用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;
/