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

Posted

技术标签:

【中文标题】如何在 Oracle 中对两个远程表之间的数据进行部分比较以避免 ORA-01652【英文标题】:How to partially compare data between two remote tables in Oracle to avoid ORA-01652 【发布时间】:2017-09-20 06:04:55 【问题描述】:

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

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

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

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

还有其他方法吗?

【问题讨论】:

参考***.com/questions/25350703/… Kaushik Nayak,这是另一个问题。 【参考方案1】:

您可以将数据拆分为多个片段并逐个进行比较。但这不是一个查询。像这样的:

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),然后逐个比较表,收集diff 变量中不同行的总数。然后你会看到循环后的总行数。 这可能需要很长时间,所以首先你需要找到最大的一块,这不会引发错误。这取决于您的系统,可以是 100 000 行、1 000 000 行或任何其他大小。 如果您需要查看行本身,而不仅仅是数量,您可以以相同的方式将它们复制到临时表中。

【讨论】:

记得检查远程数据库中没有本地数据库的ID。 @APC,感谢您的建议!你的意思是完全外连接? 不一定。您可以将此解决方案扩展到remote ID minus local ID @Dmitry,能否请教一下,如何修改查询,我需要查看 column1 的值? @ViktorPredybaylo 很难给出确切的建议,因为在大表的情况下,您将获得大量数据,而且很难查看。例如,您可以使用dbms_output 输出它们,或者使用硬编码限制手动过滤为select &lt;columns&gt; from table where id between 1 and 10000 minus select &lt;columns&gt; from table@dblink where id between 1 and 10000。在这种情况下,您只会看到所需数据的一部分,但您可以逐部分查询它们。【参考方案2】:

“如果表太大,我收到以下错误”

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

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

“还有其他方法吗?”

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

    使用键在本地数据库中而不是在远程数据库中查找记录 使用键在远程数据库中而不是在本地数据库中查找记录 在候选记录集中消除前两步的记录

如果公共记录集仍然太大,您可以通过连接所有列并使用 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

【讨论】:

【参考方案3】:

尝试改用“NOT IN”。

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

“减”操作需要排序,这会导致从 oracle 服务器的 PGA 内存中占用大量内存,如果不够,还会从临时段中占用。 “不在”有时也使用排序,但通常不会。

此外,如果您只需要表 A 中的数据而不需要表 B 中的数据,并且不需要从结果中排除重复项,那么“NOT IN”是正确的选择。

【讨论】:

以上是关于如何在 Oracle 中对两个远程表之间的数据进行部分比较以避免 ORA-01652的主要内容,如果未能解决你的问题,请参考以下文章

在Oracle数据库中,如何对两个有关联关系的表进行分页?

Toad:自动在两个 Oracle 表之间进行每日传输?

在关系数据库中对相同实体之间的多个多对多关系进行建模

oracle 两表数据对比---minus

oracle 两表数据对比---minus

坑向: 关于在Navicat中对Oracle数据库表空间的数据文件进行重命名和修改路径时报错ORA-01511,ORA-01121,ORA-01110的解决办法