暂无图片
暂无图片
6
暂无图片
暂无图片
暂无图片

一次归档暴涨的排查:不是数据库的问题

最近碰到一个挺典型的案例,记录一下排查过程。

现象

归档日志突然暴涨。导致归档目录满。平时每天 600M 到 800M,某天开始连续多天冲到 11G、15G 以上,而且没有回落迹象。

这种情况一般就两个方向:写入量突然变大,或者有什么任务在持续制造 redo。

第一步:查 TOP SQL

先拉了一下高消耗 SQL:

SELECT * FROM ( SELECT sql_id, executions, buffer_gets, disk_reads FROM v$sql ORDER BY buffer_gets DESC ) WHERE ROWNUM <= 10;

确实看到一条显眼的 UPDATE:

UPDATE MZYS_BRCF CF SET CF.OPERATIONTIME = TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS') WHERE ...

执行次数高、扫描量大、带 EXISTS 子查询——第一眼很像问题 SQL。但冷静想想,这类操作很常见,不至于把归档直接打到 15G+,方向应该不在这。

关键线索:时间线对不上

翻了一下变更记录:3 月 14 日新增了用户 TXCJX,归档暴涨从 3 月 20 日才开始,中间差了将近一周。

这个延迟很有意思。大概率是新功能上线之后,数据逐渐积累,到一定量级才开始放量——不是瞬间触发的,而是"养大了才炸"。

顺着这个思路,去查 JOB。

找到真正的原因

顺着这个思路,先查了一下 shared pool 里和这张表相关的 SQL:

SELECT sql_id, sql_text FROM v$sql WHERE sql_text LIKE '%TXCRMYY_JX_DET%';

结果很说明问题。sql_id = dd0kvh81az21j 的 INSERT 和 sql_id = 118fz5vvdb9j8 的 DELETE 各出现了八九次,说明这两条 SQL 在短时间内被反复执行。同时还能看到 JOB 的调度入口:

-- 118fz5vvdb9j8(反复出现) delete from "TXCJX"."MVIEW_TXCRMYY_JX_DET" -- dd0kvh81az21j(反复出现) INSERT /*+ BYPASS_RECURSIVE_CHECK */ INTO "TXCJX"."MVIEW_TXCRMYY_JX_DET" select ... from view_TXCRMYY_JX_DET@db_qazhis -- JOB 调度入口 dbms_refresh.refresh('"TXCJX"."MVIEW_TXCRMYY_JX_DET"');

这已经是实锤了,不是推断。接着去查 JOB 确认细节:

SELECT schema_user, what FROM dba_jobs WHERE schema_user = 'TXCJX';

结果是:

dbms_refresh.refresh('"TXCJX"."MVIEW_TXCRMYY_JX_DET"');

物化视图刷新任务。继续往下看:

SELECT mview_name, refresh_method FROM dba_mviews WHERE owner = 'TXCJX';

REFRESH_METHOD = COMPLETE

再看调度频率:SYSDATE + 10/24/60,每 10 分钟一次。

然后看实际执行的 SQL:

INSERT INTO TXCJX.MVIEW_TXCRMYY_JX_DET SELECT ... FROM view_TXCRMYY_JX_DET@db_qazhis

通过 DBLINK 从远程库拉数据。

问题就很清楚了

把这几件事合在一起看:

COMPLETE 刷新的本质不是"更新",是先 DELETE 整张表,再重新 INSERT 一遍。物化视图大约 18 万行,每 10 分钟执行一次,一天下来是 144 次。

粗算一下:18 万行 × 144 次 ≈ 2600 万行写入,每次还是 DELETE + INSERT 的组合,redo 翻倍。

600M 涨到 15G,完全合理,甚至算是"正常结果"。

为什么这个设计容易踩坑

这个方案把三个风险叠在了一起:

COMPLETE 刷新本身代价就高,每次都是全量重建,不是增量更新。DBLINK 的场景通常也做不了增量,因为远程库的数据结构不一定有时间戳或版本字段可以用。再加上 10 分钟这个频率,一天 144 次,任何单次的代价都会被无限放大。

这三件事单独拎出来可能都不是大问题,但叠在一起,redo 放大几乎是必然的结果。

怎么处理

第一步先降频,把 10 分钟改成 1 小时或者按天跑,归档立刻能降下来,用于止血。

根本上要改刷新方式。数据量大的情况下不应该用 COMPLETE。理论上可以通过 DBLINK 带 WHERE 条件做增量,但这里的数据源是远程库上的一张视图 view_GLZRMYY_JX_DET@db_qazhis,视图本身不一定有时间戳,底层基表的字段能不能透传出来也不确定。跨库的情况下,触发器、LogMiner 这些手段也都用不上。所以增量能不能做,得先确认远程视图里有没有可靠的增量字段:

WHERE JFSJ > last_sync_time -- 前提是这个字段可信且有索引

如果字段不存在或者不可信,增量就做不了,降频比强行改增量更稳,根据业务对数据实时性的实际要求来定,从 10 分钟改成每小时甚至每天,redo 会成比例下降。

尽量避免 DELETE 全表,如果还是要全量刷,可以改用 MERGE,只更新有差异的行,减少不必要的 redo 生成。

小结

这次归档暴涨,本质不是数据库出了什么问题,而是数据同步方式选错了。全量刷新 + DBLINK + 高频执行,三者叠加,redo 就一定会炸。

遇到类似情况,排查顺序基本是:有没有大批量写入、有没有定时任务、有没有"全量操作"。不要上来就怀疑数据库本身,先把写入行为摸清楚。

最后修改时间:2026-03-25 09:46:30
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论