外观
Oracle 锁等待与等待事件分析
锁的基本概念
锁类型
Oracle 数据库中的锁分为多种类型,根据不同的操作和资源对象进行分类:
DML 锁
- 行级锁 (TX锁):对表中的行进行锁定,防止其他事务修改同一行
- 表级锁 (TM锁):对表结构进行锁定,确保 DML 操作的完整性
- TM0:插入操作
- TM2:更新操作
- TM3:删除操作
- TM4:表锁定操作
- TM5:行共享 (RS)
- TM6:行排他 (RX)
- TM7:共享 (S)
- TM8:共享排他 (SX)
- TM9:排他 (X)
DDL 锁
- 排他 DDL 锁 (X锁):防止其他会话修改对象结构
- 共享 DDL 锁 (S锁):允许并发查询对象结构
- 可中断解析锁 (BR锁):用于解析 SQL 语句时的对象引用
系统锁
- 闩锁 (Latch):保护内存结构的轻量级锁
- 互斥锁 (Mutex):保护共享内存的更轻量级锁
- 库缓存锁:保护 SQL 语句的执行计划
- 库缓存钉扎:防止 SQL 语句的执行计划被老化
等待事件概述
等待事件分类
Oracle 等待事件主要分为以下几类:
空闲等待事件
- 指会话处于空闲状态,不消耗系统资源
- 示例:SQLNet message from client、SQLNet message to client
非空闲等待事件
- 指会话正在等待某种资源或操作完成
- 主要子类:
- 锁定等待:如 enq: TX - row lock contention
- I/O 等待:如 db file sequential read、db file scattered read
- CPU 等待:如 CPU time
- 网络等待:如 SQL*Net more data from client
- 并发等待:如 latch free、enq: HW - contention
- 应用等待:如 application wait
- 配置等待:如 log file sync、log buffer space
锁等待诊断方法
查看当前锁等待情况
使用 V$LOCK 和 V$SESSION 视图
sql
SELECT
s.sid,
s.serial#,
s.username,
s.status,
s.program,
l.type,
l.lmode,
l.request,
o.owner,
o.object_name,
o.object_type
FROM
v$lock l
JOIN v$session s ON l.sid = s.sid
LEFT JOIN dba_objects o ON l.id1 = o.object_id
WHERE
s.username IS NOT NULL
ORDER BY
s.sid;使用 V$SESSION_WAIT 视图查看等待事件
sql
SELECT
sid,
serial#,
username,
program,
event,
p1,
p2,
p3,
wait_time_micro / 1000000 AS wait_seconds
FROM
v$session_wait
WHERE
event NOT LIKE 'SQL*Net%'
AND event NOT LIKE 'rdbms%message%'
AND username IS NOT NULL
ORDER BY
wait_seconds DESC;识别阻塞会话
使用 V$SESSION_BLOCKERS 视图 (12c+)
sql
SELECT
blocker_sid,
blocked_sid,
blocking_session_status,
wait_event_text
FROM
v$session_blockers
ORDER BY
blocker_sid;使用阻塞链查询
sql
SELECT
LEVEL,
s.sid,
s.serial#,
s.username,
s.program,
s.status,
s.event,
s.wait_class
FROM
v$session s
CONNECT BY PRIOR s.sid = s.blocking_session
START WITH s.blocking_session IS NULL
AND s.username IS NOT NULL
AND s.status = 'ACTIVE';死锁处理
死锁的产生原因
死锁是指两个或多个会话相互等待对方释放锁资源,导致所有会话无法继续执行的情况。常见原因:
- 事务设计不合理,持有锁的时间过长
- 应用程序并发访问同一组资源的顺序不一致
- 缺少适当的索引导致全表扫描
- 长事务未及时提交或回滚
查看死锁信息
查看最近的死锁日志
sql
SELECT
*
FROM
v$diag_info
WHERE
name = 'Default Trace File';分析死锁跟踪文件
使用 tkprof 工具分析死锁跟踪文件:
bash
tkprof /u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_1234.trc /tmp/deadlock_analysis.txt sys=no使用 DBA_HIST_ENQUEUE_STAT 视图查看历史死锁情况
sql
SELECT
sample_time,
event,
username,
sql_id,
session_id,
blocking_session,
wait_time_micro / 1000000 AS wait_seconds
FROM
dba_hist_active_sess_history
WHERE
event LIKE '%deadlock%'
ORDER BY
sample_time DESC;解决死锁问题
- 识别死锁会话:使用上述查询找到死锁的会话 ID
- 终止阻塞会话:
sql
ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;- 分析死锁原因:
- 检查应用程序逻辑,确保资源访问顺序一致
- 添加适当的索引减少锁竞争
- 优化长事务,减少锁持有时间
- 使用
FOR UPDATE NOWAIT或FOR UPDATE WAIT n避免长时间等待
等待事件详细分析
常见 I/O 等待事件
db file sequential read
- 含义:单个数据块的顺序读取
- 常见原因:索引扫描、回滚段读取、排序段读取
- 优化方法:
- 优化 SQL 语句,减少逻辑读
- 调整索引设计
- 增加数据缓存大小
- 优化存储系统性能
db file scattered read
- 含义:多个数据块的分散读取,通常用于全表扫描
- 常见原因:全表扫描、索引快速全扫描
- 优化方法:
- 添加适当的索引
- 优化 SQL 语句,避免不必要的全表扫描
- 调整
db_file_multiblock_read_count参数 - 考虑分区表设计
log file sync
- 含义:会话等待 redo 日志缓冲区的内容写入磁盘
- 常见原因:频繁的提交操作、 redo 日志文件性能差
- 优化方法:
- 减少不必要的提交操作
- 优化 redo 日志存储(使用高速存储)
- 增加 redo 日志组和成员数量
- 调整
commit_write参数
常见锁定等待事件
enq: TX - row lock contention
- 含义:行级锁竞争
- 常见原因:多个会话同时修改同一行数据
- 优化方法:
- 减少事务持有锁的时间
- 优化应用程序逻辑,避免热点数据
- 使用乐观锁定机制
- 考虑分区表设计,分散热点数据
enq: TX - index contention
- 含义:索引块竞争
- 常见原因:多个会话同时插入索引的同一叶子块
- 优化方法:
- 使用反向索引(对于递增列)
- 使用分区索引
- 调整序列缓存大小
- 考虑使用全局临时表
enq: TM - contention
- 含义:表级锁竞争
- 常见原因:DDL 操作与 DML 操作冲突、外键约束缺失索引
- 优化方法:
- 为外键约束添加索引
- 避免在高峰时段执行 DDL 操作
- 使用
ON DELETE CASCADE或ON DELETE SET NULL选项
常见并发等待事件
latch free
- 含义:等待获取闩锁
- 常见原因:内存结构竞争、闩锁持有时间过长
- 优化方法:
- 调整共享池大小
- 优化 SQL 语句,减少硬解析
- 调整闩锁相关参数
- 使用绑定变量
library cache pin
- 含义:等待获取库缓存钉扎
- 常见原因:SQL 语句解析竞争、PL/SQL 程序编译
- 优化方法:
- 使用绑定变量减少硬解析
- 避免频繁编译 PL/SQL 程序
- 调整共享池大小
性能优化策略
锁优化策略
减少锁持有时间:
- 尽量缩短事务长度
- 避免在事务中执行不必要的操作
- 及时提交或回滚事务
优化锁粒度:
- 使用行级锁代替表级锁
- 合理设计表结构和索引
- 考虑使用分区表
避免锁竞争:
- 避免热点数据
- 实现合理的并发控制机制
- 使用乐观锁定
优化应用程序逻辑:
- 确保资源访问顺序一致
- 避免长事务
- 实现适当的超时机制
等待事件优化策略
I/O 等待优化:
- 优化存储系统性能
- 调整数据库参数(如
db_cache_size、db_file_multiblock_read_count) - 优化 SQL 语句,减少 I/O 操作
- 考虑使用 SSD 存储
锁定等待优化:
- 优化锁设计
- 减少锁持有时间
- 避免锁竞争
并发等待优化:
- 调整共享池大小
- 使用绑定变量
- 优化 SQL 语句,减少硬解析
19c 和 21c 版本差异
锁等待诊断增强
Oracle 19c 增强
- 引入了
V$SESSION_BLOCKERS视图,更直观地显示阻塞关系 - 增强了
V$SQL_MONITOR视图,提供更详细的锁等待信息 - 改进了 AWR 报告中的锁等待分析
Oracle 21c 增强
- 引入了
DBMS_LOCK_MONITOR包,提供更强大的锁监控功能 - 增强了自动诊断功能,能够自动检测和报告锁相关问题
- 改进了死锁检测算法,减少死锁发生的可能性
- 引入了
V$LOCK_HISTORY视图,提供锁历史信息
等待事件新特性
Oracle 19c 新等待事件
PGA memory operation:PGA 内存操作等待gc current block 3-way:RAC 环境下的 3 路当前块等待
Oracle 21c 新等待事件
buffer cache scan:缓冲区缓存扫描等待direct path read temp (clustered):集群环境下的临时表空间直接路径读取enq: UL - contention:统一审计锁竞争
生产环境最佳实践
监控与告警配置
设置锁等待告警阈值:
- 对于 enq: TX - row lock contention,设置等待时间超过 60 秒告警
- 对于阻塞会话,设置阻塞链长度超过 3 级告警
- 对于死锁,设置立即告警
定期分析锁等待情况:
- 每天生成锁等待报告
- 每周分析锁等待趋势
- 每月进行一次全面的锁优化评估
实现自动诊断:
- 使用 Oracle 自动诊断库 (ADR) 监控锁相关问题
- 配置自动通知机制,及时发现和处理锁问题
预防锁问题的最佳实践
应用程序设计:
- 实现合理的事务设计
- 使用绑定变量
- 确保资源访问顺序一致
- 实现适当的超时机制
数据库设计:
- 为外键约束添加索引
- 合理设计表和索引结构
- 考虑使用分区表
- 避免使用不必要的唯一约束
运维管理:
- 定期收集统计信息
- 定期检查和优化长事务
- 避免在高峰时段执行 DDL 操作
- 监控并优化锁等待情况
常见问题 (FAQ)
如何快速识别阻塞会话?
使用以下查询可以快速识别阻塞会话:
sql
SELECT
s.sid,
s.serial#,
s.username,
s.program,
s.status,
s.event,
s.wait_class,
s.blocking_session
FROM
v$session s
WHERE
s.blocking_session IS NOT NULL
OR s.sid IN (SELECT blocking_session FROM v$session WHERE blocking_session IS NOT NULL)
ORDER BY
s.blocking_session NULLS FIRST;如何查看锁等待的具体 SQL 语句?
sql
SELECT
s.sid,
s.serial#,
s.username,
s.program,
s.event,
s.sql_id,
t.sql_text
FROM
v$session s
LEFT JOIN v$sql t ON s.sql_id = t.sql_id
WHERE
s.status = 'ACTIVE'
AND s.username IS NOT NULL
AND s.wait_class != 'Idle'
ORDER BY
s.sid;如何避免死锁?
- 确保应用程序访问资源的顺序一致
- 减少事务持有锁的时间
- 实现适当的超时机制
- 为外键约束添加索引
- 避免长事务
- 使用乐观锁定机制
如何优化 enq: TX - row lock contention 等待事件?
- 优化应用程序逻辑,避免热点数据
- 增加适当的索引,减少锁竞争
- 调整事务隔离级别
- 使用
FOR UPDATE NOWAIT或FOR UPDATE WAIT n避免长时间等待 - 考虑使用分区表设计,分散热点数据
如何分析锁等待历史数据?
使用 AWR 报告或 DBA_HIST_ACTIVE_SESS_HISTORY 视图查看历史锁等待情况:
sql
SELECT
sample_time,
event,
username,
sql_id,
session_id,
blocking_session,
wait_time_micro / 1000000 AS wait_seconds
FROM
dba_hist_active_sess_history
WHERE
event LIKE '%lock%'
OR event LIKE '%enq%'
ORDER BY
sample_time DESC;19c 和 21c 在锁管理方面有什么主要区别?
- Oracle 21c 引入了更强大的锁监控功能,如
DBMS_LOCK_MONITOR包 - 21c 增强了自动诊断功能,能够自动检测和报告锁相关问题
- 21c 改进了死锁检测算法,减少死锁发生的可能性
- 21c 引入了
V$LOCK_HISTORY视图,提供锁历史信息 - 21c 增加了新的等待事件,如统一审计锁竞争
总结
锁等待与等待事件分析是 Oracle 数据库性能优化的重要组成部分。DBA 需要掌握锁的基本概念、等待事件的分类和诊断方法,能够识别和解决锁相关问题。在实际生产环境中,应建立完善的监控和告警机制,定期分析锁等待情况,采取有效的优化策略,预防锁问题的发生。
随着 Oracle 版本的升级,锁管理和等待事件诊断功能不断增强,DBA 应充分利用这些新特性,提高数据库的性能和可靠性。通过合理的设计、优化和管理,可以有效减少锁等待和等待事件对数据库性能的影响,确保数据库系统的稳定运行。
