长事务的危害
主要危害:锁无法释放
行级锁
行级锁长时间无法释放,导致其他事务的等待。
当前读会对数据加行锁,事务提交前无法释放。
其他事务更新相同数据时会等待锁,造成更新性能差。
解决办法:调整innodb_lock_wait_timeout参数,锁等待超时时间。默认值为50,即等待50秒后仍未获取到锁时,当前语句报错。如果等待时间过长,可适当缩短此参数。
容易产生死锁。
长事务的锁长时间不能事务,容易与其他事务产生死锁。
死锁指的是两个事务都依赖对方的锁释放。
解决办法:innodb_deadlock_detect,主动的死锁检测。默认开启该功能,发现死锁时回滚代价较小的事务。
MDL锁(元数据锁)
MDL锁(元数据锁)hold住大量事务,造成Mysql奔溃。
事务访问数据时,会自动给表增加MDL读锁。
事务修改元数据时,会自动给表加MDL写锁。
遇见锁不兼容时,申请MDL锁的事务会形成一个队列。
示例:Tx A查询时获取到了MDL读锁,Tx B等带Tx A释放MDL读锁后增加MDL写锁,Tx C、D等待增加MDL读锁。
解决办法
alter table之前,查看是否有长事务还未提交。
查看长事务:information_schema库INNODB_TRX表。
查看锁的情况。
information_schema库INNODB_LOCKS表。
查看阻塞的事务。
information_schema库INNODB_LOCK_WAITS表。
Mysql 8.0新增performance_schema。
查看锁的情况,data_locks表。
查看锁等待,data_lock_waits表。
查看MDL锁,metadata_locks表。
业务上的建议
控制长事务,没必要情况下不开启事务。
数据修改(当前读)尽量放在事务后面,降低锁时间。
总结
长事务可能会造成行锁(死锁)、MDL锁等待。
可以通过参数调整,降低锁影响。
可以通过系统表识别长事务和锁。
业务上尽量将加锁的操作后移动,降低锁时间。