面试宝典:Oracle数据库latch: redo copy等待事件处理过程

在这里插入图片描述

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. 产生过程详解

用户进程Redo Copy闩锁重做日志缓冲区LGWR进程请求获取闩锁授予闩锁复制重做记录释放闩锁进入等待队列等待(latch: redo copy)loop[等待]授予闩锁复制重做记录释放闩锁alt[闩锁可用][闩锁不可用]通知日志写入(必要时)用户进程Redo Copy闩锁重做日志缓冲区LGWR进程
  1. 用户进程生成重做记录
    当执行DML操作时,会生成重做记录
  2. 请求redo copy闩锁
    进程需要获取一个redo copy闩锁
  3. 检查闩锁可用性
    • 如果可用 → 获取闩锁
    • 如果不可用 → 进入等待队列
  4. 复制重做记录
    获取闩锁后,将重做记录复制到重做日志缓冲区
  5. 释放闩锁
    复制完成后立即释放闩锁
  6. 通知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;  -- 需重启
补丁与升级
  1. 关键补丁
    • Bug 13354175:应用11.2.0.4.210119+ PSU
    • Bug 21382587:安装12.1.0.2.220719补丁
    • Bug 29936857:19c中应用Jan 2023 RU
  2. 升级建议
    • 19c引入自适应重做优化
      ALTER SYSTEM SET "_redo_adaptive_latching"=TRUE;  -- 默认开启
      
硬件与架构优化
  • 升级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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值