Java 截断表最优解

Java 截断表最优解,java,oracle,performance,plsql,spring-integration,Java,Oracle,Performance,Plsql,Spring Integration,我创建了一个spring集成工作流,将数据从csv加载到oracle数据库。这是一个集群环境,其中每个节点处理一个csv文件并将数据加载到临时表中 临时表的结构:(在AccountNumber上的索引) 我有一个spring集成rabbitmq配置,它将文件名发布到队列。集群中的每个节点只拾取一个文件,从文件系统(共享文件系统和oracle数据库)读取csv,并将数据加载到临时表中。(每个csv的大小为2GB) 加载临时表中的所有数据后,一个节点应将数据从临时表移动到与临时表具有相同结构的主表

我创建了一个spring集成工作流,将数据从csv加载到oracle数据库。这是一个集群环境,其中每个节点处理一个csv文件并将数据加载到临时表中

临时表的结构:(在
AccountNumber
上的索引)

我有一个spring集成rabbitmq配置,它将文件名发布到队列。集群中的每个节点只拾取一个文件,从文件系统(共享文件系统和oracle数据库)读取csv,并将数据加载到临时表中。(每个csv的大小为2GB)

加载临时表中的所有数据后,一个节点应将数据从临时表移动到与临时表具有相同结构的主表

主表:(关于
账号的索引

我创建了一个存储过程,它从主表中删除现有的帐号,并在主表中加载帐号

一旦数据移动到主表,我将在过程结束时从临时表中删除数据

我的问题是截断此表的最佳方式是什么

问题:假设我的主表中有这个记录

主表:

账号ItemId ItemValue
-----------------------------------
123456 5 XYZ
123456 ABC
123456 7 DEF
现在,我从csv到temp表中获取以下条目:

AccountNumber ItemId ItemValue
------------------------------------
123456 5 FGH
现在我的主表应该只有一个值。应删除ItemId为6和7的行

账号ItemId ItemValue
-------------------------------------
123456 5 FGH
我可以通过合并实现这一点吗

场景1

在将数据加载到临时表之前截断此表是否更好?(两个独立的数据库事务,一个用于截断表,另一个用于数据移动)

(这将在队列中发布文件名之前调用) 加载前分批清理临时表的一个过程

步骤1:

创建或替换过程可清除
是
v_numberRows int:=20000;
开始
环

从临时删除,其中rownum从我的Oracle ish角度来看,您建议的两个选项都没有。原因如下:

  • 通过首先将数据加载到临时表中,然后将其复制到主表中,可以将作业加倍
  • 逐行处理是一步一步地慢
  • 使用循环提交可能会导致ORA-01555错误
  • 删除(
    DELETE
    命令)总是比截断(
    TRUNCATE
    )慢
建议:为了避免使用临时表,请使用外部表功能,该功能使用CSV文件,就像使用普通Oracle表一样

这意味着一切都可以在两个声明中完成:

-- Delete rows from the MAIN table whose ACCOUNT_NO exists in the CSV file
delete from main m
where exists (select null 
              from external_table t
              where t.account_no = m.account_no
             );

-- Insert rows into the MAIN table
insert into main (col1, col2, ...)
select col1, col2 from external_table;

或者-哪一种可能执行得最好-您可以
更新表中已存在的
科目号
的值,并且
仅插入不存在的行;不要使用两个命令,而是使用一个快速的
MERGE
语句(也称为upsert)


使用
MERGE
,您不需要在此处加载、从此处删除、从此处插入到此处。。。非常整洁,就像我说的,很快。根本不需要PL/SQL。

从我的Oracle ish观点来看,您建议的两个选项都没有。原因如下:

  • 通过首先将数据加载到临时表中,然后将其复制到主表中,可以将作业加倍
  • 逐行处理是一步一步地慢
  • 使用循环提交可能会导致ORA-01555错误
  • 删除(
    DELETE
    命令)总是比截断(
    TRUNCATE
    )慢
建议:为了避免使用临时表,请使用外部表功能,该功能使用CSV文件,就像使用普通Oracle表一样

这意味着一切都可以在两个声明中完成:

-- Delete rows from the MAIN table whose ACCOUNT_NO exists in the CSV file
delete from main m
where exists (select null 
              from external_table t
              where t.account_no = m.account_no
             );

-- Insert rows into the MAIN table
insert into main (col1, col2, ...)
select col1, col2 from external_table;

或者-哪一种可能执行得最好-您可以
更新表中已存在的
科目号
的值,并且
仅插入不存在的行;不要使用两个命令,而是使用一个快速的
MERGE
语句(也称为upsert)


使用
MERGE
,您不需要在此处加载、从此处删除、从此处插入到此处。。。非常整洁,就像我说的,很快。根本不需要PL/SQL。

为什么要使用临时表?既然使用的是spring integration,请逐行读取文件(因为它们是2gb文件),并发送每一行进行处理。您可以让队列中的多个使用者获取文件。是的,我在每个节点上配置了rabbitmq侦听器,每个节点接收一个csv文件->解析它->在临时表中加载数据。csv 1->1节点->解析它->临时表csv 2->2节点->解析它->最后的临时表任意一个节点->使用前面提到的store proc将数据从临时表合并到主表。我不发送行,而是发送一个文件名..进一步从文件系统读取csv。你的意思是我应该批量处理csv行,rabbitmq使用者应该读取行而不是文件?是的,我的意思是你可以让你的使用者逐行读取文件,然后发送下一个通道以将行转换为值对象,然后如果你需要对另一个通道进行一些处理,否则,只需将value对象传递给保存它的DAL即可。我只是不明白你为什么用临时表?为什么不直接将文件保存到主表中?为什么使用临时表?既然使用了spring integration,请逐行读取文件(因为它们是2gb文件),并发送每一行进行处理。您可以让队列中的多个使用者获取文件。是的,我有rabb的配置
-- Delete rows from the MAIN table whose ACCOUNT_NO exists in the CSV file
delete from main m
where exists (select null 
              from external_table t
              where t.account_no = m.account_no
             );

-- Insert rows into the MAIN table
insert into main (col1, col2, ...)
select col1, col2 from external_table;
merge into main m
  using (select t.account_no, t.col1, t.col2, ...
         from external_table t
        ) x
on m.account_no = x.account_no
when matched then update set m.col1 = x.col1,
                             m.col2 = x.col2, ...
when not matched then insert (account_no, col1, col2, ...)
                      values (x.account_no, x.col1, x.col2, ...);