mysql 执行sql文件_Mysql中sql执行如此慢

我们经常发现,往往执行一条简单的查询语句,但是很长时间都没有返回,今天我们看看是什么原因导致的 第一类:查询长时间不能返回 执行下面语句
select  *  from  t where id =1;
等待MDL锁 我们按照下面操作,看看会发生什么呢

bda98eefe1febcb80dfc1522fbe7b7ae.png

我们发现sql语句很长时间都不见返回响应,我们先看一下他的状态,发现果然是被锁住了.

668d0dacec562035b04724a5e941aa58.png

此类问题我们直接可以找到谁持有MDL的写锁,直接kill. 可以用查询sys.schema_table_lock_waits这张表,我们就可以直接找到阻塞的process id ,把这个连接用kill命令断开即可(mysql启动的时候设置performation_schema=on)

b1ee35fce220062b08da2aab61feb8ef.png        等待flush

下面我们说另外一种查询被阻塞的情况,当一个线程正好对表进行flush操作,本身这个线程执行的很快,但是如果这个线程flush线程被其他线程阻塞,最终会导致阻塞表t的查询,如下图所示

f0329f306ec6a0691b57f5c5c9e83ece.png

sessionA中,我们故意调用一次sleep(1),默认执行10万秒,这个时候t表是打开的,使用flush去关闭表t,就必须等待sessionA结束,同时也会阻塞sessionC

bc87d458bd1ae1e3bd3a807904c9e038.png

等待行锁 首先,我们看看下面sql语句
mysql> select * from t where id=1 lock in share mode; 
要执行上面语句的时候,这个记录就会要加读锁,如果这个时候已经有一个事物在这行记录上持有一个写锁,我们select 语句就会被阻塞。

dc723980f8cc53bac6db8295fe364e93.png

b961eb8d1ed48d733b5b5913696be218.png

这个问题并并不难分析,问题是如何查出谁占着这个写锁,如果你用的mysql5.7,可以使用下面语句
mysql> select * from t sys.innodb_lock_waits where locked_table=`'test'.'t'`\G

7ed0234326b4752fb4dbdb3c4b831667.png

可以看到4号线程就是阻塞的罪魁祸首,因此只要干掉他就可以了, 不过,这里不应该显示kill  query 4,这个命令是指把正在执行的语句停止,但是我们的update语句已经执行完成了,这样是无法去掉id=1的行锁. 实际上,kill 4才有效,也就是直接断开这个连接,这里连接被断开的时候,会自动回滚这个连接里面正在执行的线程,也就是释放id=1上的行锁.

第二类:查询慢

我们执行下面语句
select *  from t where c=50000 limit 1;
有字段c没有索引,这个语句只能全表扫描,因此要扫描5万行,再看看慢日志的记录.

93db5a3cae3be6d70cacc3ab7262a8e0.png

发现扫描了50000行,消耗时间13.5毫秒,看起来很快,但是目前数据的数据只有10万行数据,如果数据量到千万级别,这个sql就会消耗很多时间。 我们在看看另外sql,如下图
select *  from t where id=1select *  from t where id=1 lock in share mode

37b1151ecd0d8d90940dd4da43b4a328.png

按照上面操作我们再看看对应的慢查询日志

0d621554300dda4a3e23b03b165a41f5.png

14455af5a54ed6312d1ec74ed7a77c9c.png

我们发现lock in share mode加锁操作居然时间比没有加锁的查询块了,超出了我们的预期,我们再看看每个sql查询结果

59805feaed14352bc12b868e12966c84.png

此时我们就知道原因了,是因为session A先用start transaction with consistent snapshot启动了一个事物,然后sessionB才进行更新语句,然后在执行完100万次update语句后,此时的id是处于下图的状态

88c706183a8dabbb1064090281f28c2c.png

发现session B生产100万回滚日志(undo log),此时lock in share mode的sql语句,是当前读,因此会直接读到100001,速度很快,但是select *  from t where id=1,是一致性读,因此从1000001开始,依次执行undo log,执行100万次,才会把1返回.

果对您有一丝丝帮助,麻烦点个关注,也欢迎转发,谢谢

扫码关注 9bfba48c2a840376bb4961ebf8a1f93a.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值