1. 首页 > DB2教程 > 正文

DB2教程FG065-DB2锁等待与死锁解决实战

风哥教程参考DB2官方文档Locking、Deadlock、Performance等内容,详细介绍锁等待与死锁的监控、分析和解决方法。更多视频教程www.fgedu.net.cn

目录大纲

Part01-锁机制概述

1.1 DB2锁类型

DB2锁类型:

  • 意向锁(Intent Lock):IS、IX、SIX
  • 行锁(Row Lock):S、U、X、NS、NW
  • 表锁(Table Lock):S、U、X、IN、IS、IX、SIX
  • 表空间锁索引锁

1.2 锁兼容性

请求锁 IS IX S SIX U X
IS 兼容 兼容 兼容 兼容 兼容 不兼容
IX 兼容 兼容 不兼容 不兼容 不兼容 不兼容
S 兼容 不兼容 兼容 不兼容 兼容 不兼容
SIX 兼容 不兼容 不兼容 不兼容 不兼容 不兼容
U 兼容 不兼容 兼容 不兼容 不兼容 不兼容
X 不兼容 不兼容 不兼容 不兼容 不兼容 不兼容

1.3 隔离级别

  • UR(Uncommitted Read):未提交读,允许脏读
  • CS(Cursor Stability):游标稳定性,默认级别
  • RS(Read Stability):读稳定性
  • RR(Repeatable Read):可重复读,最高隔离级别

Part02-锁监控工具

2.1 监控命令

# 查看锁等待
GET SNAPSHOT FOR LOCKS ON FGEDB;

# 查看应用快照
GET SNAPSHOT FOR APPLICATIONS ON FGEDB;

# 查看表锁
SELECT
SUBSTR(TABSCHEMA, 1, 20) AS TABSCHEMA,
SUBSTR(TABNAME, 1, 30) AS TABNAME,
LOCK_MODE,
LOCK_OBJECT_TYPE,
LOCK_STATUS,
AGENT_ID
FROM SYSIBMADM.LOCKS_HELD
ORDER BY TABSCHEMA, TABNAME;

# 查看行锁
SELECT
SUBSTR(TABSCHEMA, 1, 20) AS TABSCHEMA,
SUBSTR(TABNAME, 1, 30) AS TABNAME,
LOCK_MODE,
LOCK_OBJECT_TYPE,
ROW_ID,
AGENT_ID
FROM SYSIBMADM.LOCKS_HELD
WHERE LOCK_OBJECT_TYPE = ‘ROW’
ORDER BY TABSCHEMA, TABNAME;

# 查看锁等待
SELECT
LOCK_NAME,
LOCK_OBJECT_TYPE,
LOCK_WAIT_MODE,
SUBSTR(TABSCHEMA, 1, 20) AS TABSCHEMA,
SUBSTR(TABNAME, 1, 30) AS TABNAME,
AGENT_ID,
AGENT_ID_HOLDING_LK,
LOCK_WAIT_START_TIME
FROM SYSIBMADM.LOCKWAITS;

2.2 事件监控器

# 创建死锁事件监控器
CREATE EVENT MONITOR DEADLOCK_MON FOR DEADLOCKS
WRITE TO FILE ‘/db2events/deadlock’
MAXFILES 10
MAXFILESIZE 1000
MANUALSTART;

# 启动事件监控器
SET EVENT MONITOR DEADLOCK_MON STATE = 1;

# 查看事件监控器数据
SELECT * FROM TABLE(EVMON_FORMAT_UE_TO_TABLES(‘DEADLOCK_MON’, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -1, 0)) AS t;

# 查看死锁事件
SELECT
SUBSTR(DEADLOCK_ID, 1, 20) AS DEADLOCK_ID,
DEADLOCK_TIMESTAMP,
SUBSTR(PARTICIPANT_NO, 1, 10) AS PARTICIPANT_NO,
SUBSTR(APPL_NAME, 1, 30) AS APPL_NAME,
SUBSTR(STMT_TEXT, 1, 100) AS STMT_TEXT
FROM DEADLOCK_EVENT
ORDER BY DEADLOCK_TIMESTAMP DESC;

# 停止事件监控器
SET EVENT MONITOR DEADLOCK_MON STATE = 0;

# 删除事件监控器
DROP EVENT MONITOR DEADLOCK_MON;

2.3 管理视图

# 查看当前锁
SELECT
h.AGENT_ID AS HOLDING_AGENT,
w.AGENT_ID AS WAITING_AGENT,
SUBSTR(h.TABSCHEMA, 1, 20) AS TABSCHEMA,
SUBSTR(h.TABNAME, 1, 30) AS TABNAME,
h.LOCK_MODE AS HOLDING_MODE,
w.LOCK_MODE AS WAITING_MODE,
h.LOCK_OBJECT_TYPE
FROM SYSIBMADM.LOCKS_HELD h
INNER JOIN SYSIBMADM.LOCKWAITS w
ON h.LOCK_NAME = w.LOCK_NAME;

# 查看锁等待时间
SELECT
AGENT_ID,
SUBSTR(APPL_NAME, 1, 30) AS APPL_NAME,
LOCK_WAIT_TIME,
LOCK_MODE,
SUBSTR(TABSCHEMA, 1, 20) AS TABSCHEMA,
SUBSTR(TABNAME, 1, 30) AS TABNAME
FROM SYSIBMADM.APPLICATIONS
WHERE LOCK_WAIT_TIME > 0
ORDER BY LOCK_WAIT_TIME DESC;

# 查看应用执行的SQL
SELECT
AGENT_ID,
SUBSTR(APPL_NAME, 1, 30) AS APPL_NAME,
SUBSTR(STMT_TEXT, 1, 200) AS STMT_TEXT,
STMT_EXEC_TIME,
TOTAL_USR_CPU_TIME,
TOTAL_SYS_CPU_TIME
FROM SYSIBMADM.TOP_DYNAMIC_SQL
ORDER BY STMT_EXEC_TIME DESC
FETCH FIRST 20 ROWS ONLY;

Part03-锁等待分析

3.1 锁等待原因

常见锁等待原因:

  • 长事务持有锁时间过长
  • 并发更新同一行数据
  • 索引缺失导致全表扫描
  • 隔离级别过高
  • 批量操作没有合理提交
  • 锁升级(行锁升级为表锁)

3.2 锁等待解决

# 优化SQL使用合适的隔离级别
# 使用UR(Uncommitted Read)
SELECT * FROM ORDERS WITH UR;

# 使用CS(Cursor Stability)
SELECT * FROM ORDERS WITH CS;

# 使用RS(Read Stability)
SELECT * FROM ORDERS WITH RS;

# 优化更新语句
# 只更新需要的列
UPDATE ORDERS
SET ORDER_STATUS = ‘PAID’,
UPDATE_TIME = CURRENT TIMESTAMP
WHERE ORDER_ID = ‘O001’;

# 使用SKIP LOCKED避免锁等待
SELECT ORDER_ID, ORDER_STATUS
FROM ORDERS
WHERE ORDER_STATUS = ‘PENDING’
SKIP LOCKED DATA
FETCH FIRST 10 ROWS ONLY;

# 配置锁超时
UPDATE DATABASE CONFIGURATION USING LOCKTIMEOUT 30;

# 配置死锁检测
UPDATE DATABASE CONFIGURATION USING DLCHKTIME 10000;

# 配置锁列表大小
UPDATE DATABASE CONFIGURATION USING LOCKLIST 4096;
UPDATE DATABASE CONFIGURATION USING MAXLOCKS 20;

# 禁用锁升级
ALTER TABLE ORDERS LOCKSIZE ROW;

# 强制断开持有锁的连接
FORCE APPLICATION (12345);

# 断开所有连接
FORCE APPLICATION ALL;

Part04-死锁解决

4.1 死锁场景

典型死锁场景:

  • 会话1:更新表A,等待表B
  • 会话2:更新表B,等待表A
  • 互相等待,形成死锁

4.2 死锁解决方法

# 1. 统一更新顺序
# 所有应用都按相同顺序更新表
UPDATE TABLE_A SET … WHERE …;
UPDATE TABLE_B SET … WHERE …;

# 2. 减少事务持有锁的时间
# 尽量缩短事务长度
BEGIN
UPDATE ORDERS SET ORDER_STATUS = ‘PAID’ WHERE ORDER_ID = ‘O001’;
UPDATE INVENTORY SET QUANTITY = QUANTITY – 1 WHERE PRODUCT_ID = ‘P001’;
COMMIT;
END;

# 3. 避免在事务中进行用户交互
# 不要在事务中间等待用户输入

# 4. 使用更低的隔离级别
# 使用CS代替RR或RS
SET CURRENT ISOLATION = CS;

# 5. 优化索引,避免表锁
CREATE INDEX IDX_ORDER_CUSTOMER ON ORDERS(CUSTOMER_ID);

# 6. 设置合理的锁超时
UPDATE DATABASE CONFIGURATION USING LOCKTIMEOUT 30;

# 7. 分析死锁事件
# 使用死锁事件监控器
SELECT
DEADLOCK_TIMESTAMP,
PARTICIPANT_NO,
APPL_NAME,
STMT_TEXT
FROM DEADLOCK_EVENT
WHERE DEADLOCK_TIMESTAMP > CURRENT TIMESTAMP – 1 HOUR
ORDER BY DEADLOCK_TIMESTAMP DESC;

# 8. 应用级别重试
# 在应用中捕获死锁异常并重试
try:
# 执行事务
except DeadlockException:
# 等待一段时间后重试
time.sleep(1)
# 重试事务

Part05-风哥经验总结与分享

5.1 锁问题排查步骤

  1. 查看是否有锁等待(SYSIBMADM.LOCKWAITS)
  2. 查看持有锁的应用(SYSIBMADM.LOCKS_HELD)
  3. 查看等待锁的应用正在执行的SQL
  4. 分析锁等待的原因
  5. 制定优化方案并实施
  6. 验证优化效果

5.2 锁优化建议

问题 优化方案
锁等待多 降低隔离级别,优化SQL,创建索引
死锁频繁 统一更新顺序,缩短事务,使用SKIP LOCKED
锁升级 增大LOCKLIST,设置LOCKSIZE ROW
长事务 拆分事务,合理提交,避免用户交互

5.3 运维要点

  • 配置死锁事件监控器
  • 定期检查锁等待情况
  • 建立锁问题告警
  • 及时优化慢SQL
  • 合理配置LOCKTIMEOUT
  • 定期分析死锁事件
更多视频教程www.fgedu.net.cn
学习交流加群风哥微信: itpux-com
风哥Oracle/MySQL/PostgreSQL/Greenplum/DB2/Redis等数据库培训课程,10年一线实战经验,企业级培训,真正掌握数据库核心技术!

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息