【线上故障记录】MySQLTransactionRollbackException: Lock wait timeout exceeded

数据同学反馈凌晨1-2点会出现连接系统MySQL数据库等待锁超时

com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

InnoDB事务等待一个行级锁的时间最长时间默认值是50秒(单位是秒),超过这个时间就会放弃。一个事务A试图访问一行数据,但是这行数据正在被另一个innodb事务B锁定,此时事务A就会等待事务B释放锁,等待超过innodb_lock_wait_timeout设置的值就会报错。

最直接的解决方案,就是调整innodb_lock_wait_timeout超时参数(治标不治本):

第一种在MySQL的配置文件中加入,然后重启MySQL

innodb_lock_wait_timeout = 500

第二种直接执行如下命令

set global innodb_lock_wait_timeout=500;

一、慢SQL排查流程

1、根据Druid的监控查看慢SQL,发现超过100S的慢SQL:

SELECT
* 
FROM
	( SELECT * FROM rule_result WHERE org_id = '67303' AND state = 0 AND exec_date = '2022-12-25' ) result 
WHERE
	exec_result = 0 
ORDER BY
	person_idcard ASC 
	LIMIT 0,
	10

explain解释执行,选择的索引是Order By后的idcard索引。子查询就没有走索引,所以出现了慢SQL:

优化后:

SELECT
	person_name AS NAME,
	person_idcard AS idcard,
	person_phone AS phone,
	org_id AS companyId,
	org_name AS companyName,
	dept_name AS deptName,
	rule_name AS ruleName,
	exec_date AS execDate,
	exec_result AS execResult,
	org_id AS orgId,
	window_value AS windowValue,
	type_name AS peopleTypeName,
	person_idcard_code AS idcardCode,
	window_start AS windowStart 
FROM
	( SELECT * FROM kp_rule_result WHERE org_id = '67303' AND state = 0 AND exec_date = '2023-01-04' ) result 
ORDER BY
	person_idcard ASC 

explain解释执行,选择子查询的索引,效率更高,只需要1点几秒(直接去掉身份证排序也行):

2、慢SQL排查完成后,两天内是好了,不过后来数据同学发现要先删表再写入中间结果,数据量量大时间太慢导致他的其他事务等待锁中断了。


二、慢SQL的影响

2.1、什么是MySQL慢查询呢?

其实就是查询的SQL语句耗费较长的时间。正常情况下,MySQL是不会自动开启慢查询的,且如果开启的话默认阈值是10秒

具体耗费多久算慢查询呢?这其实因人而异,有些公司慢查询的阈值是100ms,有些的阈值可能是500ms,即查询的时间超过这个阈值即视为慢查询。

# slow_query_log 表示是否开启
mysql> show global variables like '%slow_query_log%';
+---------------------+--------------------------------------+
| Variable_name       | Value                                |
+---------------------+--------------------------------------+
| slow_query_log      | OFF                                  |
| slow_query_log_file | /var/lib/mysql/0bd9099fc77f-slow.log |
+---------------------+--------------------------------------+

# long_query_time 表示慢查询的阈值,默认10秒
show global variables like '%long_query_time%';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |

2.2、MySQL慢查询危害
 
1、当表是Myisam表,对表有慢查询,不阻塞Select,对该表的其他DML、DDL操作都会被阻塞。
 
2、当表是Innodb表,当表上有慢查询,不阻塞Select 和DML,其他的DDL操作都会被阻塞,比如出现waiting for table metadata lock。

为啥会造成DDL操作阻塞?

众所周知,InnoDB引擎默认加的是行锁,但锁其实都是加在索引上的,如果筛选条件没有建立索引,会降级到表锁。而慢查询有一大部分原因都是因为没加索引导致的,所以慢查询时间过长,就会导致表锁的时间也很长,如果这时候执行DDL就会造成阻塞。

综上,当数据库中存在慢查询时,是比较危险的,当执行备份、create index、alter  table 、flush table 等操作时就会造成数据库的等待。

2.3、如何避免慢查询

1、对查询SQL,进行压测,该加索引就加索引;

2、如果有索引,进行explain执行计划分析避免索引失效的情况;


参考链接:

Mysql 异常:MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction - 简书

你可能感兴趣的:(MySQL,MySQL慢查询的影响)