MySQL 笔记整理(19) --为什么我只查一行的语句,也执行这么慢?

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: MySQL 笔记整理(19) --为什么我只查一行的语句,也执行这么慢?笔记记录自林晓斌(丁奇)老师的《MySQL实战45讲》(本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除)19) --为什么我只查一行的语句,也执行这么慢?  需要说明一下,如果MySQL数据库本身就有很大的压力,导致数据库服务器CPU占用率很高或ioutil(IO利用率)很高,这种情况下所有的语句执行都有可能变慢,不属于我们今天的讨论范围。

MySQL 笔记整理(19) --为什么我只查一行的语句,也执行这么慢?

笔记记录自林晓斌(丁奇)老师的《MySQL实战45讲》

(本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除)

19) --为什么我只查一行的语句,也执行这么慢?

  需要说明一下,如果MySQL数据库本身就有很大的压力,导致数据库服务器CPU占用率很高或ioutil(IO利用率)很高,这种情况下所有的语句执行都有可能变慢,不属于我们今天的讨论范围。为了便于描述,我们构造一个表,基于这个表来说明问题。这个表有两个字段id和c,并且我们事先插入了10万行记录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mysql> CREATE TABLE t (
  id int(11) NOT NULL,
  c int(11) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB;

delimiter ;;
create procedure idata()
begin
  declare i int;
  set i=1;
  while(i<=100000)do
    insert into t values(i,i);
    set i=i+1;
  end while;
end;;
delimiter ;

call idata();
第一类:查询长时间不返回

  执行如下语句 select * from t where id = 1;结果很长时间不返回结果,这是为什么呢?一般这种情况,大概率是表t被锁住了。这种时候我们就需要show processlist命令来查看当前语句处于什么状态了。然后根据每种状态,分析原因,如何复现以及如何处理。

等MDL锁:

  当我们使用show processlist命令时如果看到了 Waiting for table metadata lock的结果,就表示有一个线程正在表t上请求或者持有MDL写锁,把select语句堵住了。我们可以这么来复现:

 Session A通过lock table命令持有表t的MDL写锁,而session B的查询需要获取MDL读锁。所以,session B进入等待状态。而这类问题的处理方式,就是找到持有MDL写锁的家伙,然后把它kill掉。但是,由于在show processlist的结果里面,session A的Command列是“Sleep”,导致查找起来不方便。不过有了performance_schema和sys系统库以后,就方便多了。(MySQL启动时需要设置performance_schema=on,相比于设置为off,会有10%的性能损失)。通过查询sys.schem_table_lock_waits这张表,我们就可以直接找出造成阻塞的process id,把这个连接用kill命令断开即可。

等flush

  如果我们的show processlist看到了"Waiting for table flush",说明现在有一个线程正要对表t做flush操作。MySQL里面对表做flush操作的用法,一般有下面两个:

1
2
3
flush tables t with read lock;

flush tables with read lock;
  如果指定了表t的话,代表只关闭表t,如果不指定具体的表名,则表示关闭MySQL里的所有打开的表。但正常情况下,这两个语句执行起来都很快,触发它们也被别的线程堵住了。

  所以,出现Waiting for table flush状态的可能情况是:有一个flush tables命令被别的语句堵住了,然后它又堵住了我们的select语句。你可以按下面的方式复现:

  这样在session A中每行都会调用sleep(1),这样表t一直是被session"打开",然后,session B的flush tables命令要去关闭表t,就需要等待session A的查询结束。这样,session C要再次查询的话,就会被flush命令堵住了。这个例子的处理方式很前面的一样,就不再赘述了。

等行锁:

  经过上面的考验,我们的select语句终于来到了引擎里

1
mysql> select *from t where id - 1 lock in share model;
  由于访问id=1这个记录时要加读锁,如果这个时候已经有一个事务在这行记录上持有一个写锁,我们的select语句就会被堵住。复现步骤如下:

  这时如果你使用show processlist命令会发现statistics。我们来看复现步骤,sessionA启动了事务,占用写锁,还不提交,是导致sessionB被堵住的原因。这个问题不难分析,但问题是怎么查出是谁占用了这个写锁,如果你的MySQL5.7或以上版本,你可以通过sys.innodb_lock_waits表查到,查询命令是:

1
mysql> select * from t sys.innodb_lock_waits where locked_table='test'.'t'G
  但这里有一个需要注意的地方,当你查出罪魁祸首,比如线程4,你不能直接使用kill query 4;这个命令表示停止4号线程当前正在执行的语句,而这个方法其实是没有用的。因为占有行锁的是update语句,这个语句已经是之前执行完成了的,现在执行kill query,无法让这个事务去掉id=1的行锁。实际上,kill 4 才有效。也就是说直接断开这个连接。这里隐含的一个逻辑是,连接被断开的时候,会自动回滚这个连接里面正在执行的线程,也就释放了id=1的行锁。

第二类:查询慢

  我们先来看一条sql语句

1
mysql>select * from t where c=50000 limit 1;
  由于字段c上没有索引,这个语句只能走id主键顺序扫描,因此需要扫描50000行。你可以先在慢查询日志里确认一下。为了确保被慢查询日志记录下来,你可以先执行set long_query_time=0。将慢查询日志的时间阈值设置为0.虽然实际上你可能会看到返回结果不是很慢,但有一个原则是这样:坏查询不一定是慢查询。我们这个例子里面只有10万行记录,数据量大起来的话,执行时间就会线性涨上去了。

  扫描行数多,执行慢,这个很好理解。我们再来看一个只扫描了一行,但是执行很慢的语句。执行的语句是这样的。

1
mysql>select * from t where id=1;
 它的查询日志是这样的:

  还是这个查询,如果我们再加上 lock in share model,执行时间居然会变快:

  这是为什么呢?按理来说,加上了锁不应该更慢吗?我们再来看一个提示信息,下图是这两个语句的执行输出结果:

我们的第一个查询返回的结果是c=1,而带lock in share mode的语句返回的是c=1000001。如果你还是没有头绪,也别着急,我们来看看复现步骤:

你看到了,session A先用start transaction with consistent snapshot命令启动了一个事务,之后sessionB才开始执行update语句。SessionB执行完100万次update语句后,id=1这一行处于什么状态呢?你可以从下图找到答案:

  session B 更新完成100万次,生成了100万个回滚日志(undo log).带lock in share mode的SQL语句,是当前读,因此会直接读到10000001这个结果,所以速度很快;而select * from t where id = 1这个语句,是一致性读,因此需要从1000001开始,依次执行updo log,执行了100万次一行,才将结果1返回。

  注意,undo log里面的记录其实是“把2改成1”这样,而不是图中的“-1”;

原文地址https://www.cnblogs.com/dogtwo0214/p/10741624.html

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6月前
|
关系型数据库 MySQL
【MySQL实战笔记】07 | 行锁功过:怎么减少行锁对性能的影响?-01
【4月更文挑战第18天】MySQL的InnoDB引擎支持行锁,而MyISAM只支持表锁。行锁在事务开始时添加,事务结束时释放,遵循两阶段锁协议。为减少锁冲突影响并发,应将可能导致最大冲突的锁操作放在事务最后。例如,在电影票交易中,应将更新影院账户余额的操作安排在事务末尾,以缩短锁住关键行的时间,提高系统并发性能。
66 4
|
27天前
|
Java 关系型数据库 MySQL
自动化测试项目实战笔记(一):JDK、Tomcat、MySQL、Jpress环境安装和搭建
这篇文章是关于自动化测试项目实战笔记,涵盖了JDK、Tomcat、MySQL、Jpress环境的安装和搭建过程,以及测试用例和常见问题总结。
46 1
自动化测试项目实战笔记(一):JDK、Tomcat、MySQL、Jpress环境安装和搭建
|
6月前
|
SQL 存储 关系型数据库
Mysql优化提高笔记整理,来自于一位鹅厂大佬的笔记,阿里P7亲自教你
Mysql优化提高笔记整理,来自于一位鹅厂大佬的笔记,阿里P7亲自教你
|
3月前
|
SQL 关系型数据库 MySQL
SQL语句编写的练习(MySQL)
这篇文章提供了MySQL数据库中关于学生表、课程表、成绩表和教师表的建表语句、数据插入示例以及一系列SQL查询练习,包括查询、排序、聚合和连接查询等操作。
|
3月前
|
SQL 存储 关系型数据库
运维笔记.MySQL.基于mysqldump数据备份与恢复
运维笔记.MySQL.基于mysqldump数据备份与恢复
51 0
|
3月前
|
SQL 关系型数据库 MySQL
【go笔记】使用sqlx操作MySQL
【go笔记】使用sqlx操作MySQL
|
5月前
|
存储 关系型数据库 MySQL
Mysql优化之索引相关介绍(笔记)
索引查找从顶层节点开始查找,通过key值,也就是主键的值进行比较,最终定位到存储数据的叶子节点上面,从叶子节点取出响应的数据。
57 0
Mysql优化之索引相关介绍(笔记)
|
6月前
|
存储 SQL 关系型数据库
MySQL万字超详细笔记❗❗❗
MySQL万字超详细笔记❗❗❗
151 1
MySQL万字超详细笔记❗❗❗
|
5月前
|
存储 关系型数据库 MySQL
技术笔记:MySQL数据库优化详解(收藏)
技术笔记:MySQL数据库优化详解(收藏)
56 0
|
5月前
|
SQL 关系型数据库 MySQL
技术笔记:python连接mysql数据库
技术笔记:python连接mysql数据库
80 0