为何查询数据很少,却慢的离谱,在我请教了隔壁新来的阿里大佬后

本文已收录GitHub,更有互联网大厂面试真题,面试攻略,高效学习资料等git

这篇文章主要记录,形成查询数量不大的状况下,形成查询缓慢的缘由,以及相应的解决方法。github

环境说明:面试

MySQL 版本 5.7.27
隔离级别:RRsession

锁等待形成查询速度很慢

MDL 锁

如开启以下事务:ide

为何查询数据很少,却慢的离谱,在我请教了隔壁新来的阿里大佬后

Session A 持有表 t MDL 写锁。Session B 须要 MDL 读锁。这时读写锁互斥,Session B 被阻塞。性能

flush 阻塞

flush 操做通常来讲很快就能执行完,当经过查询进程状态后,看到被 flush 操做被阻塞,通常都是由其余语句引发的。学习

以下面事务:日志

为何查询数据很少,却慢的离谱,在我请教了隔壁新来的阿里大佬后

Session A 在扫描每一行时会休眠1s,而 Session B 的 flush tables t; 须要关闭表 t,要等 Session A 结束。后面的 Session C 被 Session B 阻塞了。code

flush 的操做示范:orm

#  flush 表 t
flush tables t with read lock;
# flush 全部表
flush tables with read lock;
flush 的做用在 全局锁 文章中已经介绍过,FTWRL 主要用于 MyISAM 这样不支持事务的引擎,保证在备份时视图数据一致性。

行锁

这里的行锁,用两阶段锁来体现。其余如间歇锁和 next-key 锁都会能够形成这样的现象。

为何查询数据很少,却慢的离谱,在我请教了隔壁新来的阿里大佬后

Session A 拥有 id=1 这行的写锁,Session B 想要拥有这一行的读锁,读写锁互斥。

解决方法

首先经过 show processlist; 命令查询被阻塞的状态信息。如需进一步分析的话,能够将 performance_schema=on 打开,经过查询 select blocking_pid from sys.schema_table_lock_waits; 具体形成锁等待的缘由。而后 kill掉相应的 session.

在打开 performance_schema 会有必定的性能损失。

查询确实慢

没有设置合适的索引

若是没有设置合适的索引,致使扫描行数过多,时间天然就慢了。对于这种状况,能够开启慢查询日志,查看语句的执行过程,而后进行分析。

默认状况,慢查询日志时关闭的,打开方式以下:

# 查询慢查询日志状态及存储位置
# show variables  like '%slow_query_log%';

# 查询慢查询日志的设置时间
show variables  like '%long_query%';

# 临时打开慢查询日志,MySQL 重启后失效
set global slow_query_log=1;

# 改变时间
set long_query_time=0;

事务隔离的影响

在事务究竟有没有被隔离这篇中,咱们知道表中的每行数据都有多个版本,在一致性视图开启后,视图的一致性读的结果就是经过和数据行的版本比较进而显示的结果。

为何查询数据很少,却慢的离谱,在我请教了隔壁新来的阿里大佬后

这时第一个 select 语句就会比第二个加锁的 select 语句还要慢。

由于第一个 select 语句是一致性读,须要从 100 万条回滚日志中比较直到找到适合的版本。

而第二个 select 语句是当前读,直接读取最新版本就能够了。因此花费的时间不同。

总结

形成查询小数据量,却很缓慢的缘由通常有两种,第一种多是所查数据被锁住。另外一种确实是查找过程是真的很慢。

对于数据被锁住的状况,通常会由 MDL 锁,FLUSH 操做被阻塞,行锁形成。

对于查询确实很慢来讲,考虑下索引是否设置的合适。并注意在 RR 级别下,是否因为一致性读和当前读的不一样而形成查询速度不一致的状况。

在分析缘由时,能够经过进程状态以及 sys.innodb_lock_waits 中的信息,来作出相应的处理。