将oracle中的大量数据移动到外部数据库的更快方法

时间:2011-08-18 16:09:51

标签: java sql-server oracle

我有一个java程序,用于比较数据并将数据从本地Oracle数据库移动到由在线供应商托管的外部MS SQL数据库。

目前,程序连接到执行SELECT * FROM myTABLE的MS SQL数据库,并将结果放在二维数组中。然后在Oracle中创建临时表,并使用for循环将数据插入临时表:

for (int ii = 0; ii < arr.length(); ii++){
    query = "insert into myTable_temp values "+values_from_array;
    stmt.executeQuery();
} 

使用MINUS语句查找差异:

query = "select * from ora_table minus select * from myTable_temp";
rs = stmt.executeQuery();

然后使用insert_into_mssql()方法将结果插回到MS SQL表中:

while (rs.next()){
    query = "insert into myTable values "+ values_from_rs
    insert_into_mssql(query);
}

除了我使用的表有220,000行外,这个工作正常。因此,加载数组,插入临时表,运行减去语句,然后将所有内容重新插入到mssql表中需要很长时间。

有更有效的方法吗?还是一种让它更快的方法? (dblink或任何直接连接都不会有安全限制)

5 个答案:

答案 0 :(得分:3)

是,您使用的是哪个版本的MS SQL Server?根据这一点,您可以查看SSIS或其他DTS软件。它允许您非常快速地完成您想要的任务。

答案 1 :(得分:2)

我认为创建dblink是个好主意。

答案 2 :(得分:1)

也许它可以帮助你。

Statement的新addBatch()方法允许您将多个更新语句作为一个单元组合并立即执行它们。在创建语句之后和执行之前调用addBatch():

con.setAutoCommit(false); // If some fail, we want to rollback the rest
Statement stmt = con.createStatement(  );

stmt.addBatch(
"INSERT INTO CUSTOMERS VALUES (1, "J Smith", "617 555-1323");
stmt.addBatch(
"INSERT INTO CUSTOMERS VALUES (2, "A Smith", "617 555-1132");
stmt.addBatch(
"INSERT INTO CUSTOMERS VALUES (3, "C Smith", "617 555-1238");
stmt.addBatch(
"INSERT INTO CUSTOMERS VALUES (4, "K Smith", "617 555-7823");

int[] upCounts = stmt.executeBatch(  );
con.commit(  );

请注意,我们会在创建批处理之前关闭事务自动提交。

答案 3 :(得分:0)

我可能会先将它加载到数组中,然后使用与写出时相似的技术。还可以看看并行化插入。

如果我从头开始这样做,我会将所有Oracle数据带到SQL Server并执行所有操作(从Oracle复制表,查找差异并插入SQL Server,删除从Oracle复制的表)而不是全部SQL Server数据到Oracle,只转储新记录并将它们带到SQL Server并插入它们。

SQL Server也有一个非常好的ETL工具 - SQL Server Integration Services,但除了SQL Server数据源和目标之外,我还没有很多成功使用它。

答案 4 :(得分:0)

考虑到技术限制(没有dblinks等),您可以尝试降低传输开销。 这可以通过维护同步状态和仅传输更新的行来完成。

如果我理解正确,您只需要将Oracle数据库中的更新行和新行传输到MS SQL。在非常通用的变体中,您需要在oracle_table中添加2列,其中包含复制状态:

last_update_time - 由插入或更新每个行的触发器维护。触发将列值设置为每行更改的当前日期和时间以及新行。

last_sync_time - 由插入触发器维护并由同步应用程序更改。

对于新行last_update_time := sysdatelast_sync_time := last_update_time - 1

按当前日期时间更新的每个oracle_table行更新last_update_time

在每个同步会话中执行下一个序列:

  1. oracle_table中选择last_sync_time < last_update_time的所有行,并将其插入到Oracle服务器上的某个缓冲区表中:

    begin
      execute immediate 'truncate table buffer_table';
    
      insert into buffer_table(...)
      select * from oracle_table where last_sync_time < last_update_time;
    
    end;
    
  2. 将所有行从buffer_table传输到MS SQL服务器并相应地更新myTable

  3. 将所有已同步行的更新时间提前到新值:

    update 
      oracle_table o_table
    set 
      last_sync_time = ( select buf_table.last_update_time 
                         from buffer_table buf_table
                         where buf_table.Primary_Key = o_table.Primary_Key
                       )
    where
      o_table.Primary_Key in (select Primary_Key from buffer_table)
    
  4. 请注意,在同步过程中可能会更改同步行,并且在更新buffer_table时我们需要last_sync_time的时间戳值。

    P.S。我认为MS SQL端的数据库是只读的。双向同步可以在相同的原理上完成,略有算法改进。