
Oracle 数据库 log buffer space 等待事件深度解析
1. 等待事件本质
log buffer space:
当用户进程尝试将重做记录写入重做日志缓冲区(Redo Log Buffer) 时,发现缓冲区空间不足而发生的等待。这表明重做日志缓冲区无法及时处理当前的重做生成速率。- 关键特性:
- 直接反映重做日志缓冲区的容量瓶颈
- 通常伴随高DML事务负载
- 优先于
log file sync出现,是更早期的警告信号
- 与相关等待的区别:
等待事件 触发原因 解决方向 log buffer space 日志缓冲区空间不足 扩大缓冲区/优化LGWR log file sync 提交时等待日志写入磁盘 优化I/O/批量提交 latch: redo copy 缓冲区写入争用 减少并发/优化CPU
2. 产生过程详解
- 用户进程生成重做:
DML操作产生重做记录 - 请求写入缓冲区:
尝试将重做记录写入重做日志缓冲区 - 空间检查:
- 空间充足 → 立即写入
- 空间不足 → 进入等待状态
- 唤醒LGWR:
用户进程通知LGWR需要刷新缓冲区 - LGWR写入磁盘:
将缓冲区内容写入联机重做日志文件 - 缓冲区空间释放:
写入完成后释放缓冲区空间 - 用户进程恢复:
获得空间后完成写入操作
3. 高频场景
高并发DML系统
-- 电商高峰每秒数千订单
INSERT INTO orders VALUES (...);
COMMIT; -- 高频提交
批量数据加载
-- 未使用NOLOGGING的直接路径插入
INSERT /*+ APPEND */ INTO sales_history
SELECT * FROM sales_staging; -- 生成海量重做
长时间未提交事务
BEGIN
FOR i IN 1..1000000 LOOP
UPDATE accounts SET balance=balance-10; -- 百万更新未提交
END LOOP;
COMMIT; -- 最后提交
END;
日志切换风暴
-- 日志文件过小导致频繁切换
ALTER SYSTEM SWITCH LOGFILE; -- 每分钟发生多次
RAC全局事务
-- RAC中的跨节点事务
UPDATE global_table SET status='P' WHERE node_id=2;
4. 根本原因分类
配置问题
| 问题类型 | 典型案例 |
|---|---|
| 日志缓冲区过小 | log_buffer=1M(默认值),高负载系统需要64M+ |
| 日志文件过小 | 100MB日志文件,高事务系统需要1G+ |
| 日志组不足 | 只有2组日志,频繁切换 |
I/O性能问题
- 日志磁盘慢:
重做日志位于SATA HDD而非NVMe SSD - 存储网络瓶颈:
1GbE网络无法处理高峰日志量 - 磁盘争用:
日志文件与数据文件共享同一物理磁盘
应用设计问题
- 过度提交:
-- 每条INSERT后提交 FOR i IN 1..1000000 LOOP INSERT ...; COMMIT; END LOOP; - 大批量未提交事务:
UPDATE huge_table ...; -- 更新百万行后提交
LGWR性能问题
- CPU资源不足:
LGWR进程无法获得足够CPU时间片 - 写入延迟:
I/O子系统响应时间>20ms - 归档延迟:
在归档模式下,ARCH进程跟不上日志生成速度
Oracle内部问题
- Bug导致空间回收延迟:
- Bug 12902068:11g中LGWR未及时释放缓冲区
- Bug 21382587:12c RAC中日志缓冲区管理缺陷
- Bug 29936857:19c中并行DML引发问题
5. 深度排查流程
步骤1:系统级诊断
-- 确认等待强度
SELECT event, total_waits, time_waited_micro
FROM v$system_event
WHERE event = 'log buffer space';
-- 关联重做统计
SELECT
name,
value
FROM v$sysstat
WHERE name IN (
'redo log space requests', -- 关键指标
'redo entries',
'redo size'
);
- 严重性阈值:
redo log space requests> 10/秒 +time_waited_micro> 30秒/分钟
步骤2:缓冲区配置分析
-- 日志缓冲区大小
SHOW PARAMETER log_buffer;
-- 缓冲区使用率
SELECT
ROUND((bytes - (free_bytes))/bytes*100,2) pct_used
FROM (
SELECT
(SELECT value FROM v$sysstat WHERE name='redo buffer size') bytes,
(SELECT value FROM v$sysstat WHERE name='redo buffer allocation retries') free_bytes
FROM dual
);
- 警报阈值:
pct_used > 90% 持续1分钟
步骤3:LGWR性能分析
-- LGWR进程状态
SELECT
process,
status,
seq#,
blocks,
delay -- 关键指标
FROM v$log_writer;
-- 日志文件I/O性能
SELECT
f.member,
ROUND(i.bytes/1024/1024) size_mb,
fs.phyrds,
fs.phywrts,
ROUND(fs.writetim/DECODE(fs.phywrts,0,1,fs.phywrts)*1000) avg_write_ms
FROM v$logfile f
JOIN dba_data_files i ON f.member = i.file_name
JOIN v$filestat fs ON i.file_id = fs.file_id;
- 关键指标:
delay> 0 或avg_write_ms> 15ms
步骤4:日志配置检查
-- 日志组配置
SELECT
group#,
bytes/1024/1024 size_mb,
members,
status,
archived
FROM v$log;
-- 日志切换频率
SELECT
to_char(first_time, 'YYYY-MM-DD HH24:MI') switch_time,
sequence#,
round(blocks*block_size/1024/1024) size_mb
FROM v$log_history
ORDER BY first_time DESC;
- 警报阈值:
日志切换 > 5次/分钟
步骤5:高负载事务分析
-- 高重做生成会话
SELECT
s.sid,
s.username,
s.program,
st.value redo_size
FROM v$sesstat st
JOIN v$statname sn ON st.statistic# = sn.statistic#
JOIN v$session s ON st.sid = s.sid
WHERE sn.name = 'redo size'
ORDER BY st.value DESC;
-- 关联SQL
SELECT sql_id, sql_text
FROM v$sql
WHERE sql_id IN (
SELECT sql_id FROM v$session
WHERE sid IN (&high_redo_sids)
);
步骤6:系统资源检查
-- CPU使用率
SELECT
metric_name,
ROUND(value,2) value
FROM v$sysmetric
WHERE metric_name = 'CPU Usage Per Sec'
AND group_id=2;
-- I/O负载
SELECT
filetype,
AVG(readtim) avg_read_ms,
AVG(writetim) avg_write_ms
FROM v$iostat_file
GROUP BY filetype;
步骤7:高级诊断
-- LGWR进程追踪
ALTER SYSTEM SET events 'immediate trace name processstate level 10' sid = 'LGWR';
-- 重做缓冲区转储
ALTER SESSION SET events 'immediate trace name redobuff level 10';
-- 检查Bug
SELECT patch_id, description
FROM dba_registry_sqlpatch
WHERE patch_id IN (12902068, 21382587, 29936857);
6. 根治方案
紧急处置
-- 临时减少提交频率
-- 推迟批处理作业
-- 手动切换日志释放空间
ALTER SYSTEM SWITCH LOGFILE;
-- 临时增加日志缓冲区(需重启)
ALTER SYSTEM SET log_buffer=64M SCOPE=SPFILE;
配置优化
-- 永久增加日志缓冲区
ALTER SYSTEM SET log_buffer=128M SCOPE=SPFILE;
-- 优化日志组配置
ALTER DATABASE ADD LOGFILE GROUP 4 '+FAST_DATA' SIZE 1G;
ALTER DATABASE ADD LOGFILE GROUP 5 '+FAST_DATA' SIZE 1G;
ALTER SYSTEM SWITCH LOGFILE; -- 切换到新组
ALTER DATABASE DROP LOGFILE GROUP 1; -- 删除旧组
-- 增加归档进程(归档模式)
ALTER SYSTEM SET log_archive_max_processes=4;
I/O优化
- 升级存储设备:
迁移重做日志到NVMe SSD - 分离日志存储:
ALTER DISKGROUP fast_logs ADD DISK '/dev/nvme0n1'; ALTER DATABASE ADD LOGFILE GROUP 6 '+fast_logs' SIZE 1G; - 优化RAID配置:
使用RAID 10替代RAID 5/6
应用优化
- 批量提交:
DECLARE TYPE id_array IS TABLE OF NUMBER; ids id_array := ...; BEGIN FORALL i IN 1..ids.COUNT UPDATE accounts SET balance=balance-100 WHERE id=ids(i); COMMIT; -- 批量提交 END; - NOLOGGING操作:
ALTER TABLE sales_history NOLOGGING; INSERT /*+ APPEND NOLOGGING */ INTO sales_history ...; - 最小化日志操作:
CREATE TABLE new_table NOLOGGING AS SELECT * FROM old_table;
LGWR优化
-- 关闭自适应日志同步(11gR2+)
ALTER SYSTEM SET "_use_adaptive_log_file_sync"=FALSE;
-- 增加LGWR并行度(18c+)
ALTER SYSTEM SET "_log_writer_parallelism"=4;
-- 优化写入算法
ALTER SYSTEM SET "_log_write_batch_size"=8192; -- 增加批量大小
补丁与升级
- 关键补丁:
- Bug 12902068:应用11.2.0.4.210119+ PSU
- Bug 21382587:安装12.1.0.2.220719补丁
- Bug 29936857:19c中应用Jan 2023 RU
- 升级建议:
- 19c引入智能日志缓冲区管理
ALTER SYSTEM SET "_redo_logging_adaptive"=TRUE; -- 默认开启
- 19c引入智能日志缓冲区管理
架构优化
- RAC日志分离:
-- 节点1专用日志 ALTER DATABASE ADD LOGFILE THREAD 1 GROUP 6 '+DATA_RAC1' SIZE 1G; -- 节点2专用日志 ALTER DATABASE ADD LOGFILE THREAD 2 GROUP 7 '+DATA_RAC2' SIZE 1G; - 使用In-Memory重做:
ALTER SYSTEM SET inmemory_size=10G; -- 18c+特性 - 客户端批量提交:
在应用层实现每1000行提交一次
根治原则:
解决log buffer space= 扩大日志缓冲区 + 加速日志写入(I/O优化) + 减少重做生成(批量提交/NOLOGGING)。
核心在于确保重做日志缓冲区能够处理事务高峰期的重做生成速率。
通过此方案可彻底消除日志缓冲区空间等待,保障数据库高并发事务处理能力。
欢迎关注我的公众号《IT小Chen》
1693

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



