如何在 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 <columns> from table where id between 1 and 10000 minus select <columns> from table@dblink where id between 1 and 10000
。在这种情况下,您只会看到所需数据的一部分,但您可以逐部分查询它们。【参考方案2】:
“如果表太大,我收到以下错误”
您正在执行minus
操作,这需要Oracle 对这两个表进行排序。当表很大时,Oracle 使用磁盘来保存中间排序结果。这意味着写入临时表空间;如果排序超出了您的临时表空间的容量,您将获得ORA-01652
。
首先,与您的 DBA 交谈。也许发生了很多事情,你可能会在更安静的时候有更好的运气。也许他们可以扩展 TEMP 表空间。或者他们可能能够为您的用户提供一个专用的临时表空间(可能只是为了本练习的目的而将其竖立起来 - 这取决于您在做什么以及为什么)。
“还有其他方法吗?”
这也取决于您在做什么以及为什么。对于一次性练习,您可以将任务分成多个步骤:
-
使用键在本地数据库中而不是在远程数据库中查找记录
使用键在远程数据库中而不是在本地数据库中查找记录
在候选记录集中消除前两步的记录
如果公共记录集仍然太大,您可以通过连接所有列并使用 ora_hash()
或 Oracle 的加密函数之一对它们进行散列来创建每条记录的校验和。这将为您提供两个小得多的数据块进行比较。
如果这是一个重复的练习,您需要重新考虑您的数据管理策略。也许其中一个表应该是另一个表的物化视图。
最后,请记住您必须使用两次 MINUS:A minus B
和 B 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的主要内容,如果未能解决你的问题,请参考以下文章
坑向: 关于在Navicat中对Oracle数据库表空间的数据文件进行重命名和修改路径时报错ORA-01511,ORA-01121,ORA-01110的解决办法