从select中更新或从select中更新每次提交1M记录

时间:2017-03-09 09:36:05

标签: database oracle

我已经看过十几个这样的问题,但大多数问题都得到的答案并不适用于我的案例。

首先 - 数据库是我试图从一个非常慢的网络获取数据并连接到使用VPN。

我通过数据库链接访问它。

我对我的架构表有完全的读/写访问权限,但我没有DBA权限,所以我无法创建转储,而且我没有为创建新表等提供资助。

我一直试图在本地获取数据库,除了一个表外一切都很好。

它有650万条记录和16列。 获得其中的14个没有问题,但剩下的两个是带有大量XML的Clobs。

数据传输速度很慢,很痛苦。

我试过了 基于select插入 插入全部14然后更新另外2 将表创建为 基于select条件插入,所以我只得到这么多记录并手动提交

问题主要是在事务完成之前连接丢失(或断电或VPN丢失或随机错误等),并且所有已下载的GB都将被丢弃。

正如我所说,我尝试了条件,所以我得到了一些记录,但即使这有点随机,需要我的关注。 类似的东西:

Insert into TableA 
Select * from TableA@DB_RemoteDB1 
WHERE CREATION_DATE BETWEEN to_date('01-Jan-2016') AND to_date('31-DEC-2016')

有时它有时会起作用。在几GB之后,Toad停止运行,但当我查看它的吞吐量时,它是0KB / s或几个字节/秒。

我正在寻找的是一个循环或一个游标,可以用来一次获得100000或1000000 - 提交它然后去完成剩下的工作直到完成。

这是我正在做的一次性操作,因为我们需要本地数据进行测试 - 所以我不关心它是否效率低,只要数据以块的形式引入并且提交可以使我免于再次检索它。

我已经可以计算过去3天内已经完成的大约15GB的失败下载,而我的本地表仍然有0条记录,因为我的所有尝试都失败了。

服务器:Oracle 11g

本地:Oracle 11g

尝试过的客户端:Toad / Sql Dev / dbForge Studio

感谢。

1 个答案:

答案 0 :(得分:1)

您可以执行以下操作:

begin
  loop
    insert into tablea
    select * from tablea@DB_RemoteDB1 a_remote
    where not exists (select null from tablea where id = a_remote.id)
    and rownum <= 100000; -- or whatever number makes sense for you

    exit when sql%rowcount = 0;

    commit;
  end loop;
end;
/

这假设有一个主/唯一密钥可用于检查远程表中的行是否已存在于本地密钥中 - 在此示例中,我使用了模糊的ID列,但用实际的键列替换它。

对于循环的每次迭代,它将识别远程表中本地表中不存在的行 - 这可能很慢,但是你说这里的性能不是优先级 - 然后,通过rownum,将插入的行数限制为可管理的子集。

当没有插入行时,循环终止,这意味着远程表中没有剩下的行不会在本地存在。

由于提交和where not exists检查,这应该可以重新启动。这通常不是一种好方法 - 因为它会破坏正常的事务处理 - 但是作为一次性和网络问题/约束可能是必要的。

Toad是对的,使用批量收集会(通常会显着)更快一般,因为每次循环都不会重复查询:

declare
  cursor l_cur is
    select * from tablea@dblink3 a_remote
    where not exists (select null from tablea where id = a_remote.id);
  type t_tab is table of l_cur%rowtype;
  l_tab t_tab;
begin
  open l_cur;
  loop
    fetch l_cur bulk collect into l_tab limit 100000;

    forall i in 1..l_tab.count
      insert into tablea values l_tab(i);

    commit;

    exit when l_cur%notfound;
  end loop;
  close l_cur;
end;
/

这次你可以将limit 100000更改为你认为合理的数字。这里有一个权衡,因为PL / SQL表会消耗内存,所以你可能需要试验一下来选择那个值 - 如果它太高,你可能会得到错误或影响其他用户。这里的问题较小,除了散装插件的效率稍差。

但是因为你有一个CLOB列(持有你的XML),这对你来说不起作用,正如@BobC指出的那样; insert ... select is supported over a DB link,但收集版本将从fetch中收到错误:

  

ORA-22992:不能使用从远程表中选择的LOB定位器
  ORA-06512:第10行   22992. 00000 - &#34;不能使用从远程表中选择的LOB定位器&#34;
  *原因:无法引用远程LOB列   *操作:删除对远程表中LOB的引用。