暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MYSQL-note15, mysql的慢查询

原创 YanLang 2023-06-28
151


如果 MySQL 数据库本身就有很大的压力,导致数据库服务器 CPU 占用率很高或 ioutil(IO 利用率)很高,这种情况下所有语句的执行都有可能变慢

 

今天要讨论的是一个简单的查询语句,数据库本身压力并不大的情况


 第一类:查询长时间不返回:

执行语句:select * from t where id=1;(总共10万条记录)

 

一般碰到这种情况的话,大概率是表 t 被锁住了。接下来分析原因的时候,一般都是首先执行一下 show processlist 命令,看看当前语句处于什么状态。

 

1.1)等 MDL 锁

使用 show processlist 命令查看 Waiting for table metadata lock。

session A 通过 lock table 命令持有表 t 的 MDL 写锁,而 session B 的查询需要获取 MDL 读锁。

所以,session B 进入等待状态。这类问题的处理方式,就是找到谁持有 MDL 写锁,然后把它 kill 掉。

通过查询 sys.schema_table_lock_waits这张表,我们就可以直接找出造成阻塞的 process id,把这个连接用 kill 命令断开即可。

 

1.2)等 flush

出现 Waiting for table flush 状态的可能情况是:

有一个 flush tables 命令被别的语句堵住了,然后它又堵住了我们的 select 语句


flush tables t with read lock; (只锁表T)

flush tables with read lock;(锁所有表)

session A 中,故意每行都调用一次 sleep(1),这样这个语句默认要执行 10 万秒,在这期间表 t 一直是被 session A“打开”着。

session B 的 flush tables t 命令再要去关闭表 t,就需要等 session A 的查询结束。

session C 要再次查询的话,就会被 flush 命令堵住了。

 

 

1.3)等行锁

上面是表级锁的考验,接下来进入到数据库引擎里了。

 

mysql> select * from t where id=1 lock in share mode;


由于访问 id=1 这个记录时要加读锁,如果这时候已经有一个事务在这行记录上持有一个写锁,我们的 select 语句就会被堵住。

问题是怎么查出是谁占着这个写锁。如果你用的是 MySQL 5.7 版本,可以通过 sys.innodb_lock_waits 表查到。

 

mysql> select * from t sys.innodb_lock_waits where locked_table='`test`.`t`'\G

 

 

 

第二类:查询慢

经过了重重封“锁”,我们再来看看一些查询慢的例子。


2.1)查询扫描行数多:

 

mysql> select * from t where c=50000 limit 1;

由于字段 c 上没有索引,这个语句只能走 id 主键顺序扫描,因此需要扫描 5 万行。作为确认,你可以看一下慢查询日志。扫描行数多,所以执行慢,这个很好理解

 


2.2)只扫描一行,但是执行很慢的语句:

 

mysql> select * from t where id=1;

虽然扫描行数是 1,但执行时间却长达 800 毫秒。

另外一个语句select * from t where id=1 lock in share mode,执行时扫描行数也是 1 行,执行时间是 0.2 毫秒

按理说 lock in share mode 还要加锁,时间应该更长才对啊。

 

带 lock in share mode 的 SQL 语句,是当前读,因此会直接读到 1000001 这个结果,所以速度很快;

select * from t where id=1 这个语句,是一致性读,因此需要从 1000001 开始,依次执行 undo log,执行了 100 万次以后,才将 1 这个结果返回。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论