现象描述
TDSQL Boundless 实例在运行过程中,业务侧出现死锁报错,可能伴随以下现象:
应用程序日志中出现死锁错误,错误码为
1213(ER_LOCK_DEADLOCK)。应用程序日志中出现锁等待超时错误,错误码为
1205(ER_LOCK_WAIT_TIMEOUT)。实例监控中 SQL 失败数指标升高,死锁次数不为零。
高并发场景下,部分事务被自动回滚并提示 Deadlock found when trying to get lock。
您可通过以下方式发现和确认死锁:
在 TDSQL Boundless 控制台的实例详情 > 监控告警 > 指标监控页面查看 SQL 失败数、汇总活跃线程数、死锁次数、行锁等待次数等指标,判断死锁发生频率和时间点。
在 数据库智能管家 DBbrain 的诊断优化 > 异常诊断页面查看死锁诊断事件,获取现场描述、智能分析和优化建议。
可能原因
死锁通常由多个事务相互持有对方需要的锁资源,形成等待环导致。可能原因如下:
序号 | 可能原因 |
1 | 多个事务以不同顺序访问相同的表或行,形成锁等待环。 |
2 | 事务中执行时间过长,持有锁的时间过长,增加死锁概率。 |
3 | 并发量突增,锁竞争加剧,短时间内大量事务争抢同一批资源。 |
4 | 死锁检测未开启或锁等待超时设置不合理,导致死锁无法被及时检测和解除。 |
解决思路
针对不同原因,解决思路如下:
可能原因 | 解决思路 |
事务访问顺序不一致 | 统一事务中表的访问顺序,确保并发事务按相同顺序加锁。 |
事务执行时间过长 | 拆分大事务为小事务,减少单事务持锁时间;优化事务内 SQL 执行效率。 |
并发量突增 | 业务侧进行限流或错峰执行,降低并发争抢强度。 |
死锁检测未开启 | 通过控制台开启死锁检测,并合理设置锁等待超时时间。 |
处理步骤
步骤1:查看监控指标
1. 登录 TDSQL Boundless 控制台,在实例列表中单击目标实例 ID,进入实例详情页。
2. 选择监控告警 > 指标监控页签,查看以下指标的变化趋势:
监控指标 | 说明 | 关注点 |
SQL 失败数 | 每秒失败的 SQL 数量 | 死锁发生时,失败数会突增 |
汇总活跃线程数 | 当前活跃线程数 | 并发量是否突增 |
慢查询数 | 每秒慢查询数量 | 锁等待是否导致查询变慢 |
CPU 利用率 | 实例 CPU 使用率 | 锁竞争是否导致 CPU 升高 |
死锁次数 | 每秒死锁发生次数,直接反映死锁频率 | 死锁次数是否持续不为零 |
行锁等待次数 | 每秒行锁等待次数,反映锁竞争强度 | 锁等待次数是否突增 |
行锁等待超时次数 | 每秒行锁等待超时次数,反映锁超时是否频繁 | 锁超时是否频繁出现 |
平均行锁等待时间 | 行锁平均等待耗时(毫秒),反映锁等待是否过长 | 等待时间是否持续偏高 |
当前长事务个数 | 当前长事务数量,是否存在持有锁时间过长的事务 | 长事务是否长时间持有锁 |
跨节点事务 TPS | 每秒跨节点事务数,跨分片事务更易引发死锁 | 跨节点事务是否频繁 |
重点关注 SQL 失败数突增的时间点,与业务并发高峰或批量任务执行时间是否吻合。同时关注死锁次数和行锁等待次数是否同步上升,若死锁次数持续不为零,说明存在频繁死锁;若当前长事务个数偏高,可能存在事务持有锁时间过长导致死锁。
3. 如需进行多指标关联分析,可登录 DBbrain 控制台,进入诊断优化 > 性能趋势页面,使用图表联动功能查看 CPU、内存、磁盘、QPS、慢查询等关键性能指标的时间序列曲线。若 CPU 利用率飙升但 QPS 未明显增长,且慢查询数同步上升,可能是锁竞争导致事务空转等待锁资源。详细操作请参见 性能趋势。
步骤2:查看死锁信息
1. 登录 DBbrain 控制台,在左侧导航栏选择诊断优化。
2. 在页面顶部选择数据库类型为 TDSQL Boundless,并选择目标实例 ID。
3. 单击异常诊断页签,在页面右侧选择查看实时或历史诊断信息。
4. 在诊断提示列表中,单击对应事件行进入详情。
死锁诊断事件的风险等级固定为致命。事件详情包含以下四个模块:
模块 | 排查要点 |
事件详情 | 确认风险等级为"致命",记录起止时间,用于后续与监控指标关联分析。 |
现场描述 | 被回滚的事务 ID:系统自动选择回滚的事务,通常是写数据量较少或较晚开启的事务。 requesting_sql:触发死锁的具体 SQL 语句,是定位问题根因的关键。 req_lock_range / blk_lock_range:等待方和阻塞方分别持有或等待的锁范围,帮助判断锁冲突的具体资源。 |
智能分析 | 系统对死锁根因和影响范围的分析,确认是访问顺序不一致、长事务还是并发突增导致。 |
优化建议 | 针对死锁场景给出的处理建议,据此确定后续处理方向(Kill 会话、调参数、优化 SQL)。 |

5. 切换到智能分析页签,根据系统给出的分析结论和建议,确定后续处理方向。
步骤3:查看锁等待会话
1. 在 DBbrain 控制台的诊断优化页面,单击实时会话页签。
2. 在活跃会话列表中,查看当前活跃会话的来源、执行时间和状态,重点关注以下信息:
STATE 字段为
Locked 的会话:该会话正处于锁等待状态,是锁竞争的直接表现。TIME 值较大的会话:可能正在等待锁资源,导致其他事务被阻塞。
INFO 字段:会话正在执行的 SQL 语句,帮助定位是哪个业务操作引发的锁等待。
USER 和 HOST 字段:帮助定位是哪个业务或客户端发起的会话。
3. 若发现长时间锁等待的异常会话,按以下步骤终止该会话以释放锁资源:
3.1 在活跃会话列表中,勾选待终止的会话。
3.2 单击列表右上方的 Kill 会话。
3.3 在弹出的确认对话框中,单击确定。
注意:
Kill 会话会立即终止目标会话正在执行的 SQL 与事务,未提交的事务将回滚,可能导致业务侧请求报错。请仅在确认目标会话确为异常会话后再执行该操作。终止会话需要当前账号具备实例的会话管理权限。
4. 终止会话后,可在列表上方单击 Kill 历史记录,查看已终止的会话记录。
步骤4:开启死锁检测
若死锁检测未开启,建议通过控制台开启,使系统自动检测并解除死锁。
1. 登录 TDSQL Boundless 控制台,在实例列表中单击目标实例 ID,进入实例详情页。
2. 选择参数设置 > 数据库参数页签,查找以下参数:
参数名 | 说明 | 默认值 |
tdstore_deadlock_detect | 是否开启死锁检测。开启后系统会自动检测死锁环并回滚其中一个事务。 | OFF |
tdstore_deadlock_victim | 死锁发生时选择牺牲事务的策略。 WRITE_LEAST 优先回滚写数据量较少的事务;START_LATEST 优先回滚较晚开启的事务。 | WRITE_LEAST |
3. 将
tdstore_deadlock_detect 的值修改为 ON,开启死锁检测。4. 根据业务场景设置
tdstore_deadlock_victim 的值:WRITE_LEAST:优先保护写数据量大的事务,适合以数据写入为主的场景。START_LATEST:优先保护先开启的事务,适合事务执行顺序明确的场景。5. 在目标参数所在行的参数当前值列,单击修改参数值,单击保存,在确认对话框中单击确定。
注意:
开启死锁检测会带来少量的性能开销,但在死锁频发的场景下,开启检测可以避免事务长时间阻塞,整体收益大于开销。
步骤5:调整锁等待超时时间
若锁等待超时时间设置不合理(过长或过短),可通过控制台调整
tdsql_lock_wait_timeout 参数。1. 在参数设置 > 数据库参数页签,查找
tdsql_lock_wait_timeout 参数。2. 根据业务场景调整参数值:
默认值为10秒。若业务事务执行时间较长,可适当调大,避免正常事务因锁等待被误杀。
若希望死锁和锁等待尽快被解除,可适当调小,减少业务阻塞时间。
3. 在目标参数所在行的参数当前值列,单击修改参数值,单击保存,在确认对话框中单击确定。
步骤6:优化业务事务
从业务层面优化事务设计,从根本上减少死锁发生概率。
1. 统一访问顺序:确保所有并发事务以相同的顺序访问表和行。例如,事务 A 和事务 B 都先更新表1再更新表2,避免交叉等待。
2. 缩短事务范围:
将大事务拆分为多个小事务,减少单事务持锁时间。
事务中避免包含耗时操作(如远程调用、文件 IO),尽快提交事务。
使用
SELECT ... FOR UPDATE 时,尽量只锁定需要的行,避免锁定过多资源。3. 降低并发强度:
对高并发写入场景进行限流,控制同时执行的事务数量。
批量操作分批执行,避免单批次操作锁定大量资源。
将非核心业务的写入操作错峰执行。
4. 使用合适的索引:
确保更新和删除操作使用索引定位行,避免全表扫描加锁。
无索引的更新操作会锁定大量行,大幅增加死锁概率。
步骤7:通过 DBbrain 分析慢 SQL
锁竞争往往与低效 SQL 有关,优化 SQL 可以减少锁持有时间。推荐使用 DBbrain 的慢 SQL 分析功能定位锁等待热点 SQL 并进行优化。
1. 在 DBbrain 控制台的诊断优化页面,单击慢 SQL 分析页签。
2. 选择时间范围,在 SQL 列表中单击最大锁等待时间列,按降序排列,优先找到锁等待最严重的 SQL 模板。也可按总耗时或平均执行时间降序排列,综合判断低效 SQL。
3. 单击某条聚合的慢 SQL,在右侧弹出的面板中查看执行计划、优化建议和执行耗时分布,详细操作请参见 慢 SQL 分析。
4. 重点关注以下信息:
最大锁等待时间和平均锁等待时间:锁等待时间较长的 SQL 是锁竞争的热点,优先优化。
最大扫描行数:扫描行数过多说明 SQL 未走索引或索引不合适,会锁定大量行,需添加索引。
执行计划中
type 列为 ALL 表示全表扫描,需添加索引;rows 列值过大说明扫描行数过多,锁定的行也越多。5. 根据执行计划和优化建议,进行以下优化:
为
WHERE 条件列添加索引,减少扫描和锁定行数。避免在没有索引的列上执行
UPDATE 或 DELETE。使用
LIMIT 限制单次操作影响的行数。6. 优化后回到慢 SQL 分析页面,对比优化前后的最大锁等待时间和总耗时变化,验证优化效果。
预防措施
为避免死锁问题反复发生,建议采取以下预防措施:
开启死锁检测:确保
tdstore_deadlock_detect 参数设置为 ON,使系统自动检测并解除死锁。配置告警策略:在控制台为 SQL 失败数、死锁次数、行锁等待次数等指标配置告警,及时发现死锁问题。
关注 DBbrain 异常诊断:定期查看 DBbrain 异常诊断页面的死锁诊断事件,根据智能分析和优化建议及时处理潜在风险。
定期巡检慢 SQL:通过 DBbrain 慢 SQL 分析页面定期检查慢 SQL 模板,重点关注最大锁等待时间较高的 SQL,优化低效查询以减少锁持有时间。
监控实时会话锁等待:在业务高峰期通过 DBbrain 实时会话页面关注 STATE 为
Locked 的会话数量,若锁等待会话持续增多,及时排查是否存在事务持有锁时间过长。规范事务设计:制定事务开发规范,统一表访问顺序,控制事务大小和持锁时间。
监控 SQL 失败数:定期关注控制台监控面板中的 SQL 失败数指标,若出现突增,及时排查是否存在死锁或锁等待问题。
相关文档
您还可以通过 information_schema.PROCESSLIST 查看当前会话锁等待情况。