答案是通过SHOW ENGINE INNODB STATUS命令查看LATEST DETECTED DEADLOCK部分,结合INNODB_TRX等表分析事务状态,定位死锁涉及的事务、SQL语句及锁等待关系,进而从索引优化、事务拆分、操作顺序一致等方面进行优化。
排查MySQL死锁,核心在于快速定位死锁发生的现场,并理解其根源,从而找到解决的突破口。这不仅仅是看一眼日志那么简单,更像是一场侦探游戏,需要你从蛛丝马迹中还原真相。
当MySQL发生死锁时,首先要做的是捕获死锁信息。最直接、最有效的方式就是通过
SHOW ENGINE INNODB STATUS命令来查看最新的死锁报告。这个报告会详细记录死锁涉及的事务、它们持有的锁、请求的锁以及导致死锁的具体SQL语句。
通常,在
LATEST DETECTED DEADLOCK部分,你会看到两个事务的详细信息,一个被标记为“LATEST DETECTED DEADLOCK”,另一个是“*** (2) WAITING FOR THIS LOCK TO BE GRANTED:”。前者是被选为死锁牺牲品(ROLLBACK)的事务,后者则是导致死锁发生的另一个关键事务。仔细分析这两个事务的SQL语句、它们正在操作的表和索引,以及它们各自持有的锁和正在等待的锁,就能基本还原死锁发生的场景。
SHOW ENGINE INNODB STATUS;
这个命令的输出内容非常庞大,但大部分时候,我们只需要聚焦在
LATEST DETECTED DEADLOCK这一小节。如果死锁频繁发生,可以考虑开启
innodb_print_all_deadlocks参数,让所有死锁信息都打印到MySQL错误日志中,方便后续分析。
识别死锁,很多时候是业务系统抛出异常,提示“Deadlock found when trying to get lock; try restarting transaction”时才察觉。但作为DBA或开发者,我们不能仅仅被动等待。除了前面提到的
SHOW ENGINE INNODB STATUS,还有一些主动或辅助的手段。
比如,通过查询
information_schema数据库中的
INNODB_TRX、
INNODB_LOCKS和
INNODB_LOCK_WAITS这几个表,可以实时查看当前正在运行的事务、它们持有的锁以及等待的锁。虽然这些表不会直接告诉你“死锁发生了”,但它们能帮你描绘出事务和锁的实时状态图。当发现某个事务长时间处于等待状态,并且等待的锁被另一个事务持有,而那个事务又在等待这个事务持有的锁时,死锁的苗头就已经很明显了。
我个人习惯是,一旦怀疑有死锁,除了
SHOW ENGINE INNODB STATUS,还会迅速扫一眼
INNODB_TRX,看看有没有长时间运行的事务,或者那些状态看起来有点“僵住”的事务。这个过程有点像医生问诊,除了看病历(死锁日志),还要摸脉(实时事务状态)。
SELECT
t.trx_id,
t.trx_state,
t.trx_started,
t.trx_mysql_thread_id,
t.trx_query
FROM
information_schema.innodb_trx t
WHERE
t.trx_state = 'LOCK WAIT'; -- 查找正在等待锁的事务解读死锁日志,其实就是要把
LATEST DETECTED DEADLOCK报告中的碎片信息拼凑起来,形成一个完整的死锁故事。这里面有几个关键点:
HOLDS THE LOCK(S))和它正在等待的锁(
WAITING FOR THIS LOCK TO BE GRANTED)。核心就是找到那个循环:事务A持有X,请求Y;事务B持有Y,请求X。
举个例子,你可能会看到两个事务都在更新同一张表,但一个事务先更新了ID=100的记录,然后尝试更新ID=200;另一个事务却反过来,先更新ID=200,再尝试更新ID=100。如果这两个操作都带有排他锁,那么死锁就不可避免了。这种场景下,SQL语句的顺序,以及它们背后对资源的争抢,才是我们要深挖的。
死锁的发生,往往不是偶然,背后总有其逻辑。理解这些常见的死锁场景,能帮助我们更好地预防和优化。
WHERE子
句是否使用了合适的索引。EXPLAIN是你的好朋友,用来分析SQL语句的执行计划,确保它能高效地使用索引。
SERIALIZABLE隔离级别虽然能提供最高的数据一致性,但也会引入更多的锁,增加死锁的可能性。
READ COMMITTED或
REPEATABLE READ已经足够。根据业务需求权衡隔离级别,避免过度锁定。
INSERT、
UPDATE、
DELETE时,可能会隐式地对关联表加锁,尤其是在没有为外键列创建索引时,这种风险更高。
解决死锁,很多时候是一个迭代的过程。你可能需要调整SQL语句、优化索引、修改业务逻辑,甚至调整数据库配置。关键在于,每次死锁发生,都要把它当成一次学习的机会,深入分析,找到症结,然后应用合适的策略去解决。这不光是技术的挑战,更是一种对系统和业务逻辑的深刻理解。