如何部分比较Oracle中两个远程表之间的数据以避免ORA-01652

时间:2017-09-20 06:04:55

标签: sql oracle oracle11g

我使用减运算符来比较两个表。例如:

select colmn1, ..., column10 from table
minus
select colmn1, ..., column10 from remote_table@db_link;

但是如果表格太大,我会收到以下错误

  

ORA-01652:无法在表空间TEMP中将临时段扩展128。

还有其他办法吗?

3 个答案:

答案 0 :(得分:2)

您可以将数据拆分成碎片并逐个进行比较。但它不会是一个查询。像这样:

declare
  diff number := 0;
  subdiff number;
  piece_size number := 1000;
  table_size number;
begin
  select count(*) 
    into table_size
    from table;

  for i in (select rownum r from dual connect by level <= ceil(table_size/piece_size)) loop
     select count(*)
       into subdiff
       from (select colmn1, ..., column10 from table
              where id between (i.r - 1) * piece_size and i.r * piece_size
              minus
             select colmn1, ..., column10 from remote_table@db_link
              where id between (i.r - 1) * piece_size and i.r * piece_size);
     diff := diff + subdiff;
  end loop;
  dbms_output.put_line('Total lines: ' + diff);
end;

在这里,您计算本地表中的行数,然后将其拆分为1000行(变量piece_size),并逐个比较表,收集{{1}中不同行的总数变量。然后你会看到循环后的总行数 这可能需要很长时间,所以首先你需要找到最大尺寸的块,这不会引起错误。这取决于您的系统,可能是10万行,1 000 000行或任何其他大小 如果您需要自己查看行,而不仅仅是金额,您可以以相同的方式将它们复制到临时表中。

答案 1 :(得分:2)

  

&#34;如果表太大,我收到以下错误&#34;

您正在执行minus操作,这需要Oracle对这两个表进行排序。当表很大时,Oracle使用磁盘来保存中间排序结果。这意味着写入临时表空间;如果排序超过临时表空间的容量,则会得到ORA-01652

首先,与您的DBA交谈。也许有很多种情况发生,你可能会在更安静的时候有更好的运气。也许他们可以扩展TEMP表空间。或者他们可能只为您的用户提供专用的临时表空间(可能只是为了本练习的目的而站起来 - 这取决于您正在做什么以及为什么)。

  

&#34;还有其他方式吗?&#34;

这还取决于你正在做什么以及为什么。对于一次性练习,您可以将任务分成多个步骤:

  1. 使用密钥查找本地数据库中不在远程数据库中的记录
  2. 使用密钥查找远程数据库中不在本地数据库中的记录
  3. 消除候选记录集中前两个步骤的记录
  4. 如果公共记录集仍然太大,您可以通过连接所有列并使用ora_hash()或Oracle的一个加密函数对它们进行散列来创建每个记录的校验和。这将为您提供两个比较小的数据块。

    如果这是重复练习,您需要重新考虑您的数据管理策略。也许其中一个表应该是对另一个表的物化视图。

    最后,请记住,您必须使用MINUS两次:A minus BB minus A。校验和的一个吸引人之处在于它使这项操作更容易

    select t1.id as local_id
           , t2.id as remote_id
           , case
               when  t1.id is null then 'not in local'
               when  t2.id is null then 'not in remote'
               else  'existing changed'
             end as state
    from your_table as t1
         full outer join your_table@remote_db t2
         on t1.id = t2.id
    where t1.id is null
    or t2.id is null
    or t1.check_sum != t2.check_sum
    

答案 2 :(得分:0)

尝试使用&#34; NOT IN&#34;代替。

select * 
  from employees
 where (department_id, manager_id) not in 
           (select department_id, manager_id 
              from departments ) ;

&#34;减&#34;操作需要排序,这导致从oracle服务器的PGA内存中获取大量内存,如果还不够,则从临时段中获取。 &#34;不在&#34;有时候也会使用排序,但通常不会。

此外,如果您只需要来自表A的数据而没有来自B的数据,并且不需要从结果中排除重复项,那么&#34; NOT IN&#34;是正确的选择。