MySQL死锁和卡死分析(工作中的实战,可以好好看看) |
2.问题分析
因为之前对这类问题没有什么经验,初步猜测,可能是并发查询导致了数据库某张表被死锁。
a.使用show processlist;和kill ID定位问题
show processlist
上图是数据库卡死的时候我看到的结果,可以看到state一栏,状态都是sending data的状态,我在网上查这个状态就是正在进行查询或者等待查询数据返回。Info一栏可以看到正在执行的是那条sql语句。
如果是sql并发导致了某张表被锁如何查询卡死的话,我看网上的办法是可以使用kill id的方式去强制结束sql的执行。但是我把全部正在执行的sql进程全部kill之后,数据库还是卡死状态。也就可以证明不是死锁造成的问题。(提醒:尽量不要执行执行kill操作,尤其是生产环境)
b.为了进一步证明不是死锁导致的问题,可以执行下面的几条sql
分析死锁的方法:
SELECt
trx_id AS 事务ID
,
trx_state AS 事务状态
,
trx_requested_lock_id AS 事务需要等待的资源
,
trx_wait_started AS 事务开始等待时间
,
trx_tables_in_use AS 事务使用表
,
trx_tables_locked AS 事务拥有锁
,
trx_rows_locked AS 事务锁定行
,
trx_rows_modified AS 事务更改行
FROM
information_schema.innodb_trx ;
从上图可以看见没有实物被锁定
SELECt
lock_id AS 锁ID
,
lock_trx_id AS 拥有锁的事务ID
,
lock_mode AS 锁模式
,
lock_type AS 锁类型
,
lock_table AS 被锁的表
,
lock_index AS 被锁的索引
,
lock_space AS 被锁的表空间号
,
lock_page AS 被锁的页号
,
lock_rec AS 被锁的记录号
,
lock_data AS 被锁的数据
FROM
information_schema.innodb_locks;
可以看到没有表或者索引等等呗锁定
SELECt
requesting_trx_id AS 请求锁的事务ID
,
requested_lock_id AS 请求锁的锁ID
,
blocking_trx_id AS 当前拥有锁的事务ID
,
blocking_lock_id AS 当前拥有锁的锁ID
FROM
information_schema.innodb_lock_waits;
同样没有看到有锁存在。
c.结果这些步骤基本可以确定不是死锁造成的数据库卡死的问题问题。然后我又去网上搜索了其他我觉得可能造成问题的原因
比如最大连接数:show VARIABLES like ‘%CONNECTION%’;
或者线程原因:show VARIABLES like ‘%thread%’;
show VARIABLES like ‘%lock%’;
或者是等待请求超时show variables like ‘%wait_timeout%’;
但是这些都不对,不论我改那个变量,数据库卡死的问题还是没解。
然后我想到执行的sql比较复杂,数据量也比较大,可能是性能原因导致的卡死,而非是死锁。所以在网上搜索,然后找到
show VARIABLES like ‘%buffer_pool%’; 查看buffer_pool
可以看到默认的innodb_buffer_pool_size只有可怜的8M左右,然后网上的推荐是对于服务器一般这个大小要设置为全部系统内存的3/4到4/5左右。不要太高否则可能造成系统内存不足,然后进而影响数据库的运行效率。
然后我把innodb_buffer_pool_size设到512M
SET GLOBAL innodb_buffer_pool_size= 512000000;
然后再测试,问题解决。之后我又反复的试了,将innodb_buffer_pool_size设为默认值,问题可以得到反复的验证。说明问题点就是innodb_buffer_pool_size太小导致的。
想要进一步了解innodb_buffer_pool_size和innodb_buffer_pool_instances这两个参数对数据库影响的可以看下面两篇文章
https://blog.csdn.net/kk185800961/article/details/79378313/
https://www.cnblogs.com/mydriverc/p/8296938.html
3.推荐explain这个指令
Explain + sql 可以查看SQL语句的执行计划
typedView是我建的视图,视图是使用union级联了10来张表建立的。网上的资料说没有possible_key和key的就是没有索引的。因为视图没有索引,所以只能进行全表搜索来查询,这样的话速度就会比较慢。我自己也试过了20000+数据的视图查询一条记录的时间在我自己电脑上是0.7s左右。同样大小的单表查询是0.04s左右。。从截图的申请了可以看到视图是和其他几张表进行级联查询的,这样的话导致单次查询的时间进一步增加,我这边查25条任务列表的时间大概是20s。
然后建议不要将视图和数据量很大的表进行级联查询,更不要和多张数据量很大的表级联查询,这样的话单次查询的速度会非常慢的。我这边的解决办法是将复杂的sql拆分成多步查询,然后也可以借助一部分java代码替代sql的部分操作。这样可以进一步非优化查询时间。我这边拆分sql然后加上一些java代码替代部分sql后单次查询大概是2s左右。