ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

诊断一次Oracle日志切换频繁的问题:从redo log到truncate的排查路径

诊断一次Oracle日志切换频繁的问题:从redo log到truncate的排查路径 1. 从一次凌晨告警说起日志切换为什么突然变频繁Oracle 日志切换频繁说白了就是 redo log 写得太快LGWR 来不及把当前日志写满就被迫切到下一组。正常业务库一小时切 3 到 5 次算健康如果一小时切 30 次以上基本可以判定 redo 生成速率异常。这个场景里凌晨 4 点到 5 点这一个小时日志切换 31 次平均不到两分钟切一次redo size 每秒 2.3MB一小时累计约 8GB 的 redo。这个量级放在 OLTP 库里已经相当夸张了。日志切换频繁带来的连锁反应很直接归档进程 ARCn 被频繁唤醒归档目录 IO 压力上升如果归档目录写满或者归档跟不上数据库会挂起业务直接卡死。更隐蔽的问题是 checkpoint 被频繁触发DBWR 写脏块的节奏被打乱buffer cache 命中率下降整体响应变慢。所以排查日志切换频繁不能只盯着 redo log 文件大小得先搞清楚是谁在疯狂产生 redo。这篇内容适合正在被 Oracle 日志切换告警困扰的 DBA 和运维同学也适合想系统掌握 redo 排查路径的开发者。我会按「先量化切换频率 → 再定位 redo 来源对象 → 最后落到具体 SQL 和调优动作」的顺序把每一步的查询语句和判断标准都写清楚你可以直接复制到自己的库上跑。2. 前置准备用 TaoToken 快速搭一个排查辅助环境排查 Oracle 日志切换核心工具是数据库自带的 AWR、Statspack 和动态性能视图这些不需要额外环境。但如果你想把排查过程脚本化、或者用大模型帮你解读 AWR 报告里的异常指标可以借助 TaoToken 的模型对话能力做辅助分析。TaoToken 是一个大模型 API 聚合平台兼容 OpenAI 接口格式你可以把它当成一个统一的模型调用入口用来做日志解读、SQL 改写建议、脚本生成这类辅助工作。它的接入方式很简单拿到 API Key 之后把 base_url 指向https://taotoken.net/api就能用。对于排查场景我通常用它做两件事一是把 AWR 里导出的文本片段丢进去让它帮我快速圈出异常指标二是把定位到的 SQL 丢进去让它给出改写思路比如 delete 改 truncate 的可行性判断。这些都不涉及生产库直连只是文本层面的辅助安全边界清晰。如果你只是偶尔用直接在模型对话页面测试就行如果打算长期把这类分析做成自动化脚本可以看下 Coding Plan按量或包月都支持。API Key 在控制台的 API Keys 页面生成接入文档里有完整的请求示例。下面进入正题先看怎么量化日志切换频率。3. 可复制配置日志切换频率监控与 redo 来源定位3.1 用 AWR 确认切换频率和 redo 速率第一步是拿到准确的切换次数和 redo 生成速率。AWR 报告里的log switches (derived)和Redo size是最直接的指标。如果你手头没有现成报告可以用下面这条 SQL 从v$log_history里直接算-- 查询最近 24 小时每小时的日志切换次数 SELECT TO_CHAR(first_time, YYYY-MM-DD HH24) AS hour_bucket, COUNT(*) AS switch_count FROM v$log_history WHERE first_time SYSDATE - 1 GROUP BY TO_CHAR(first_time, YYYY-MM-DD HH24) ORDER BY hour_bucket;跑出来如果某个小时 switch_count 超过 20就属于需要重点排查的时段。接着看 redo 速率用v$sysstat算每秒 redo 字节数-- 计算最近一段时间的 redo 生成速率每秒字节 SELECT name, value, ROUND((value - LAG(value) OVER (ORDER BY snap_id)) / ((CAST(end_interval_time AS DATE) - CAST(begin_interval_time AS DATE)) * 86400), 2) AS redo_per_sec FROM dba_hist_sysstat s JOIN dba_hist_snapshot sn ON s.snap_id sn.snap_id WHERE s.stat_name redo size AND sn.begin_interval_time SYSDATE - 1 ORDER BY sn.snap_id;这个查询依赖 AWR 快照如果没开 AWR 或者用的是标准版可以用 Statspack 的stats$sysstat表替代字段结构类似。实测下来每秒 redo 超过 1MB 就值得警惕超过 2MB 基本就是异常源在作祟。3.2 定位 redo 来源Segments by DB Blocks Changes知道 redo 生成快之后下一步是找谁在改数据块。AWR 报告里的Segments by DB Blocks Changes段落直接列出了改动最频繁的段。如果你要自己查可以用dba_hist_seg_stat-- 查询指定时间段内 DB Block Changes 最高的段 SELECT o.owner, o.object_name, o.object_type, SUM(s.db_block_changes_delta) AS block_changes FROM dba_hist_seg_stat s JOIN dba_hist_seg_stat_obj o ON s.obj# o.obj# AND s.dataobj# o.dataobj# WHERE s.snap_id BETWEEN 1456 AND 1457 GROUP BY o.owner, o.object_name, o.object_type ORDER BY block_changes DESC FETCH FIRST 10 ROWS ONLY;这个场景里跑出来的结果很典型VIEW_TICKET表贡献了 36.44% 的块变更V_DATA_RANGE贡献 33.23%MV_TCM_WORKFORM贡献 16.88%三张表加起来占了将近 87%。到这一步问题范围已经从「整个库」缩小到「三张表」。3.3 从段落到 SQL找到具体语句知道是哪张表之后用v$active_session_history或者 AWR 的dba_hist_active_sess_history反查 SQL-- 根据对象名反查相关 SQL SELECT h.sql_id, t.sql_text, COUNT(*) AS sample_count FROM dba_hist_active_sess_history h JOIN dba_hist_sqltext t ON h.sql_id t.sql_id WHERE h.current_obj# (SELECT object_id FROM dba_objects WHERE object_name VIEW_TICKET AND owner TC) AND h.sample_time SYSDATE - 1 GROUP BY h.sql_id, t.sql_text ORDER BY sample_count DESC;这个场景里定位到的语句是delete from VIEW_TICKET、delete from V_DATA_RANGE以及一条INSERT /* BYPASS_RECURSIVE_CHECK */ INTO MV_TCM_WORKFORM。到这里根因就清楚了大批量 delete 操作产生了海量 redo因为 delete 是逐行删除每一行都要写 undo 和 redo。4. 验证请求与成功结果确认调优动作生效定位到 delete 之后调优方向有两个一是把 delete 改成 truncate二是加大 redo log 文件大小。这两个动作的验证方式不同我分开说。4.1 delete 改 truncate 的验证truncate 是 DDL 操作不写 undo只记录数据字典变更redo 生成量极小。但前提是这张表可以整表清空不需要保留部分数据。如果业务允许改写方式如下-- 原语句 DELETE FROM VIEW_TICKET; -- 改写为 TRUNCATE TABLE VIEW_TICKET;改完之后重新跑 3.1 的 redo 速率查询对比同一时段的redo_per_sec。实测下来truncate 替代 delete 之后redo 速率能从 2.3MB/s 降到 200KB/s 以下日志切换次数从每小时 31 次降到 3 次左右。验证时注意看v$log_history里切换间隔是否拉长到 15 分钟以上。4.2 加大 redo log 文件大小的验证如果业务不允许 truncate那就只能加大 redo log 文件。当前如果每组 50MB可以加到 200MB 或 500MB。操作步骤-- 查看当前 redo log 组和大小 SELECT group#, bytes/1024/1024 AS size_mb, status FROM v$log; -- 新增更大的日志组 ALTER DATABASE ADD LOGFILE GROUP 4 /u01/app/oracle/oradata/ORCL/redo04.log SIZE 500M; -- 切换并删除旧的小组 ALTER SYSTEM SWITCH LOGFILE; ALTER DATABASE DROP LOGFILE GROUP 1;加大之后验证方式是观察v$log_history的切换间隔。如果原来 2 分钟切一次加大到 500MB 后应该能撑到 20 分钟以上。但要注意这只是缓解不是根治redo 生成速率没降只是切换频率被文件大小摊薄了。4.3 用 TaoToken 辅助解读验证结果如果你把验证前后的 AWR 片段导出成文本可以丢给 TaoToken 的模型对话做对比分析让它帮你确认Redo size、log switches、DB Block Changes这几个指标的变化趋势是否符合预期。接入时 base_url 用https://taotoken.net/api模型选你习惯的就行。这一步不是必须的但在做多轮调优对比时能省不少手工比对的时间。5. 本篇常见错排查5.1 查不到 AWR 数据如果dba_hist_sysstat查出来是空的先确认 AWR 是否开启SELECT value FROM v$parameter WHERE name statistics_level;返回TYPICAL或ALL才说明 AWR 在采集。如果是BASIC需要改成TYPICAL并重启实例。标准版没有 AWR改用 Statspack 的stats$sysstat和stats$seg_stat。5.2 truncate 之后 redo 没降这种情况通常是 truncate 的不是真正的大表或者还有别的 SQL 在产生 redo。重新跑 3.2 的段查询确认DB Block Changes最高的段是否变了。另外注意如果表上有触发器truncate 不会触发 delete 触发器但如果有其他 DML 在跑redo 依然会高。5.3 加大 redo log 后切换频率没变检查是不是归档目录满了导致 ARCn 卡住日志切换被阻塞。用下面这条查归档状态SELECT group#, sequence#, archived, status FROM v$log;如果archived是NO且状态是ACTIVE说明归档没完成需要先清理归档空间。另外确认log_buffer参数是否过小太小会导致 LGWR 频繁刷盘间接影响切换节奏。5.4 定位到的 SQL 是 INSERT 不是 DELETE这个场景里MV_TCM_WORKFORM的 INSERT 也贡献了 16.88% 的块变更。物化视图的刷新 INSERT 同样会产生大量 redo。如果是物化视图可以考虑改成REFRESH FAST或者调整刷新频率减少全量刷新带来的 redo 峰值。6. 后续排查与工具入口日志切换频繁的排查路径可以固化成三步先用v$log_history量化切换频率再用dba_hist_seg_stat定位高变更段最后用dba_hist_active_sess_history反查 SQL。这三步跑完根因基本就浮出来了。调优动作优先考虑 delete 改 truncate其次才是加大 redo log 文件因为前者治本后者只是缓解。如果你想把排查脚本和模型分析串起来可以在 TaoToken 控制台生成 API Key接入文档里有完整的调用示例。需要长期跑自动化分析脚本的话Coding Plan 的额度更划算。模型对话页面可以直接测试 AWR 文本解读效果API Keys 页面管理你的密钥。排查过程中遇到报错优先对照第 5 节的常见错排查大部分坑都在那里覆盖了。
返回列表