
Oracle 数据库 latch: redo copy 等待事件深度解析
1. 等待事件本质
latch: redo copy:
当用户进程尝试将重做记录(redo record)复制到重做日志缓冲区(Redo Log Buffer) 时发生的闩锁争用。该闩锁保护对重做日志缓冲区的并发访问。- 关键特性:
- 保护重做日志缓冲区的内存结构完整性
- 高并发DML操作的主要瓶颈之一
- 每个CPU核心通常有一个redo copy闩锁
- 与相关等待的区别:
等待事件 触发原因 保护资源 latch: redo copy 复制重做记录到缓冲区 重做日志缓冲区 latch: redo allocation 在日志缓冲区分配空间 日志缓冲区的空间管理 log file sync 提交时等待日志写入磁盘 提交的持久化
2. 产生过程详解
- 用户进程生成重做记录:
当执行DML操作时,会生成重做记录 - 请求redo copy闩锁:
进程需要获取一个redo copy闩锁 - 检查闩锁可用性:
- 如果可用 → 获取闩锁
- 如果不可用 → 进入等待队列
- 复制重做记录:
获取闩锁后,将重做记录复制到重做日志缓冲区 - 释放闩锁:
复制完成后立即释放闩锁 - 通知LGWR:
如果日志缓冲区满或提交时,唤醒LGWR进程
3. 高频场景
高并发DML操作
-- 100个会话同时执行INSERT
INSERT INTO sales VALUES (...);
批量数据加载
-- 使用直接路径插入
INSERT /*+ APPEND */ INTO orders SELECT * FROM orders_staging;
索引维护操作
-- 重建大表索引
ALTER INDEX sales_pk REBUILD;
数据归档操作
-- 大批量DELETE操作
DELETE FROM archive_table WHERE created < SYSDATE - 365;
4. 根本原因分类
系统资源问题
| 问题类型 | 典型案例 |
|---|---|
| CPU资源不足 | CPU利用率持续100%,导致进程无法快速获取闩锁 |
| 日志缓冲区过小 | log_buffer=1M(默认值),无法满足高重做生成率 |
| 闩锁数量不足 | _cpu_count设置过小(但通常不建议修改) |
应用设计问题
- 未使用批量提交:
-- 每行提交一次 FOR i IN 1..1000000 LOOP INSERT INTO my_table VALUES (...); COMMIT; -- 应每1000行提交一次 END LOOP; - 过度使用直接路径插入:
-- 高并发下使用APPEND提示 INSERT /*+ APPEND */ ... -- 产生大量重做
数据库配置问题
- 未启用NOLOGGING:
大表操作未使用NOLOGGING选项 - 日志文件组不足:
SELECT group#, members, bytes/1024/1024 size_mb FROM v$log; -- 只有2组日志,每组1个成员
Oracle内部机制
- LGWR写入延迟:
I/O性能差导致LGWR无法及时清空缓冲区 - Bug导致争用加剧:
- Bug 13354175:11g中高并发INSERT导致redo copy争用
- Bug 21382587:12c RAC中redo copy闩锁不平衡
- Bug 29936857:19c中并行DML引发争用
5. 深度排查流程
步骤1:系统级诊断
-- 确认等待强度
SELECT event, total_waits, time_waited_micro
FROM v$system_event
WHERE event = 'latch: redo copy';
-- 检查重做日志统计
SELECT name, value
FROM v$sysstat
WHERE name IN ('redo entries', 'redo size', 'redo buffer allocation retries');
- 严重性阈值:
time_waited_micro> 30秒/分钟 +redo entries> 50,000/秒
步骤2:闩锁争用分析
-- 检查redo copy闩锁争用
SELECT
ln.name,
ls.gets,
ls.misses,
ROUND((ls.misses/DECODE(ls.gets,0,1,ls.gets))*100,2) miss_ratio,
ls.sleeps
FROM v$latchholder lh, v$latch ls, v$latchname ln
WHERE ln.name LIKE '%redo copy%'
AND ln.latch# = ls.latch#;
步骤3:日志缓冲区分析
-- 日志缓冲区大小
SHOW PARAMETER log_buffer;
-- 日志缓冲区等待
SELECT
event,
total_waits,
time_waited_micro
FROM v$system_event
WHERE event IN ('redo buffer allocation retries', 'latch: redo allocation');
步骤4:高负载SQL分析
-- 高重做生成SQL
SELECT
sql_id,
sql_text,
executions,
rows_processed,
ROUND(redo_size/executions/1024) redo_kb_per_exec
FROM
(SELECT sql_id, sql_text, executions, rows_processed,
buffer_gets, disk_reads,
(elapsed_time/1000000) elapsed_sec,
io_interconnect_bytes redo_size
FROM v$sql
WHERE io_interconnect_bytes > 0
ORDER BY io_interconnect_bytes DESC)
WHERE ROWNUM <= 10;
步骤5:LGWR性能分析
-- LGWR统计
SELECT
process,
status,
seq#,
blocks,
delay
FROM v$log_writer;
-- 日志文件I/O性能
SELECT
l.group#,
l.thread#,
l.sequence#,
l.bytes/1024/1024 size_mb,
f.member,
i.bytes/1024/1024 file_size_mb
FROM v$log l, v$logfile f, v$log i
WHERE l.group# = f.group#
AND l.group# = i.group#;
步骤6:系统资源检查
-- CPU使用率
SELECT
metric_name,
ROUND(value,2) value
FROM v$sysmetric
WHERE metric_name IN ('CPU Usage Per Sec')
AND group_id=2; -- 最近1分钟
-- I/O延迟
SELECT
filetype,
AVG(readtim) avg_read_ms,
AVG(writetim) avg_write_ms
FROM v$iostat_file
GROUP BY filetype;
步骤7:高级诊断
-- 闩锁追踪
ALTER SESSION SET events 'immediate trace name latch level 10';
-- 检查Bug
SELECT patch_id, description
FROM dba_registry_sqlpatch
WHERE patch_id IN (13354175, 21382587, 29936857);
6. 根治方案
紧急处置
-- 暂时减少高DML操作
-- 将批量作业调度到低峰期
-- 临时增加日志缓冲区(需重启)
ALTER SYSTEM SET log_buffer=64M SCOPE=SPFILE;
应用层优化
- 批量提交:
-- 每1000行提交一次 FOR i IN 1..1000000 LOOP INSERT INTO my_table VALUES (...); IF MOD(i,1000)=0 THEN COMMIT; END IF; END LOOP; COMMIT; - 使用NOLOGGING:
-- 大表操作 ALTER TABLE sales NOLOGGING; INSERT /*+ APPEND NOLOGGING */ INTO sales ...; - 减少重做生成:
-- 使用SQLLoader直接路径加载 sqlldr user/pwd control=load.ctl direct=true
数据库配置优化
-- 增加日志组和成员
ALTER DATABASE ADD LOGFILE GROUP 4 '+DATA' SIZE 1G;
ALTER DATABASE ADD LOGFILE GROUP 5 '+DATA' SIZE 1G;
-- 优化LGWR性能
ALTER SYSTEM SET "_use_adaptive_log_file_sync"=FALSE; -- 11gR2+
ALTER SYSTEM SET "_log_writer_parallelism"=4; -- 18c+
-- 增加redo copy闩锁(谨慎)
ALTER SYSTEM SET "_cpu_count"=32 SCOPE=SPFILE; -- 需重启
补丁与升级
- 关键补丁:
- Bug 13354175:应用11.2.0.4.210119+ PSU
- Bug 21382587:安装12.1.0.2.220719补丁
- Bug 29936857:19c中应用Jan 2023 RU
- 升级建议:
- 19c引入自适应重做优化
ALTER SYSTEM SET "_redo_adaptive_latching"=TRUE; -- 默认开启
- 19c引入自适应重做优化
硬件与架构优化
- 升级CPU:增加更多CPU核心(因为redo copy闩锁数量与CPU数相关)
- 使用SSD:将重做日志文件放在高性能SSD上
- 分离日志存储:
ALTER DATABASE ADD LOGFILE GROUP 3 '+FAST_LOGS' SIZE 1G; - RAC负载均衡:在RAC环境中,将负载分散到不同节点
根治原则:
解决latch: redo copy= 减少重做生成(NOLOGGING) + 优化提交模式(批量) + 加速日志写入(I/O优化)。
核心在于降低每个事务的重做生成量,并优化重做日志的写入效率。
通过此方案可显著降低redo copy闩锁争用,提升数据库事务处理能力。
欢迎关注我的公众号《IT小Chen》
1062

被折叠的 条评论
为什么被折叠?



