如何高效地将100万行插入Oracle数据库表?

gpnt7bae  于 2023-05-28  发布在  Oracle
关注(0)|答案(2)|浏览(338)

我必须在Oracle数据库表中插入大约100万行,如下所示:

create table ID_NO_APPROVAL_TEST
(
    ID NUMBER(10)           not null
        primary key,
    REASON_ID         NUMBER(10)           not null,
    TAXCODE             VARCHAR2(30)         not null,
    STATUS            NUMBER(1),
    CREATE_DATE       DATE default SYSDATE not null,
    USER_CREATE       VARCHAR2(100)        not null
)

具有以下值

values(ID_SEQ.NEXTVAL,1,'xxxxxxxxxxxx2',1,sysdate,'abcxyz');

values(ID_SEQ.NEXTVAL,5,'xxxxxxxxxxxx3',1,sysdate,'abcxyz');

values(ID_SEQ.NEXTVAL,3,'xxxxxxxxxxxx3',1,sysdate,'abcxyz');

values(ID_SEQ.NEXTVAL,4,'xxxxxxxxxxxx5',1,sysdate,'abcxyz');
.....

解决此问题的最佳方法是什么?
我尝试下面的声明与10千行:

insert /*+ APPEND*/
into ID_NO_APPROVAL_TEST(ID, reason_id, TAXCODE, status, create_date, USER_CREATE)
select GET_ID_NO_APPROVAL_ID_TEST_SEQ, 275978, '100100939', 1,sysdate,'DUYNQ7' from dual
union select GET_ID_NO_APPROVAL_ID_TEST_SEQ, 1,'xxxxxxxxxxxx2',1,sysdate,'abcxyz' from dual
union select GET_ID_NO_APPROVAL_ID_TEST_SEQ, 4,'xxxxxxxxxxxx3',1,sysdate,'abcxyz') from dual
union select GET_ID_NO_APPROVAL_ID_TEST_SEQ, 7,'xxxxxxxxxxxx3',1,sysdate,'abcxyz' from dual
....

但我花了两分钟才说完这句话

qyyhg6bp

qyyhg6bp1#

INSERT VALUES用于单行。您需要一个包含大量行的行集,其中源是数据库中的另一个表。为此,使用INSERT SELECT:

INSERT INTO ID_NO_APPROVAL_TEST 
SELECT ID_SEQ.NEXTVAL, reason_id,taxcode,status,SYSDATE,user_create 
  FROM sourcetable

这可以通过增加ID_SEQ序列该高速缓存设置并启用并行dml来加速(假设您在具有CPU容量的多核数据库服务器上运行):

ALTER SEQUENCE ID_SEQ CACHE 10000
/
INSERT /*+ enable_parallel_dml parallel(8) append */ INTO ID_NO_APPROVAL_TEST 
SELECT ID_SEQ.NEXTVAL, reason_id,taxcode,status,SYSDATE,user_create 
  FROM sourcetable
cwdobuhd

cwdobuhd2#

减少每个SQL语句中运行的行数,性能将大大提高。
构建大型SQL语句效果很好,但是构建 * 巨大 * 的SQL语句可能会导致问题。具体来说,INSERT语句中的几乎所有性能时间都用于解析SQL。要验证这一点,请运行完全相同的语句两次,由于该语句已经被解析并缓存在内存中,因此运行时间几乎为零。或者,您可以跟踪语句并查看解析时间,就像我在this answer中所做的那样。
运行100万个独立的语句将花费很长时间,但是运行100万个合并在一起的语句也将花费很长时间。最佳选择取决于您的Oracle版本。在10 g或更低的情况下,我的目标是100。在19 c中,使用您的表和示例数据,1000工作得很好。使用您的表和示例数据在我的数据库上的运行时间,请参见下表。请注意,这些值在某个点之后不会线性增加。

# Rows   Seconds
------   -------
   500       0.5
  1000       1
  2000       4
  5000      22
 10000      95

理想情况下,您可以直接从另一个表插入这些数据,或者使用SQL*Loader、JDBC批处理等工具。但这并不总是可能的,只要注意每条语句的大小,用一个SQL脚本插入100万行是很好的。由于只有100万行,您无需担心并行性、UNION ALL而不是UNION、直接路径写入、序列缓存等问题。正确地调整INSERT批处理的大小可以解决99%的问题;别担心剩下的1%。

相关问题