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

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

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

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

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操作的用法,一般有下面两个:

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语句终于来到了引擎里

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表查到,查询命令是:

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语句

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

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

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

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”;

mysql中为啥只显示一条语句_MySQL 笔记整理(19) --为什么我只查一行的语句,也执行这么慢?...相关推荐

  1. mysql 只显示第一条记录_MySQL:此种查询结果,怎么仅保留第一条记录?

    select id, value from test; 查询结果如下 id value yy 123 zz 234 zz 456 仅想保留id字段的第一条记录,在5.7以下版本中使用"sel ...

  2. SQl语句查询重复数据 只显示其中一条

    SQL查询重复数据,只显示其中一条 有重复数据主要有以下几种情况: 1.存在两条完全相同的纪录 这是最简单的一种情况,用关键字distinct就可以去掉 example: select distinc ...

  3. mysql查询不超过19_mysql45讲 19.为什么我只查一行的语句,也执行这么慢?

    一般情况下,如果我跟你说查询性能优化,你首先会想到一些复杂的语句,想到查询需要返回大量的数据.但有些情况下,"查一行",也会执行得特别慢.今天,我就跟你聊聊这个有趣的话题,看看什么 ...

  4. JS实现数组每次只显示5条数据,首尾相连显示

    JS实现数组每次只显示5条数据,首尾相连显示 今天朋友问我,如何点击一个按钮,每次只展示数组中的五条数据,如果数据有13条,默认展示数组1-5,点第一次为6-10,第二次为11-13,第三次从头再来 ...

  5. 电脑的任务栏只显示一条杠,没有图标怎么解决,看这里!!!

    电脑的任务栏只显示一条杠,没有图标怎么解决,看这里!!! 问题描述 解决方法 问题描述 打开软件只有一条杠,没有图标,而且点也点不动怎么办 解决方法 鼠标单击任务栏右键 2 找到 工具栏 如图 将 K ...

  6. Oracle中各个命中率的总结及调优笔记整理

    Oracle中各个命中率的总结及调优笔记整理 关于Oracle中各个命中率的计算以及相关的调优 1)Library Cache的命中率: .计算公式:Library Cache Hit Ratio = ...

  7. mysql相同姓名只显示第一条_SQL中遇到多条相同内容只取一条的最简单实现方法...

    SQL中经常遇到如下情况,在一张表中有两条记录基本完全一样,某个或某几个字段有些许差别, 这时候可能需要我们踢出这些有差别的数据,即两条或多条记录中只保留一项. 如下:表timeand 针对time字 ...

  8. mysql主表一条数据对应从表多条数据需要只显示一条

    场景,在关联表查询时,主表的一条数据查询时对应了从表中的多条数据,但是需求要求只显示主表对应的一条从表数据. 解决方案: 在查询最后加上GROUP BY去重 原来的SQL: select * from ...

  9. mysql中值换行显示为乱码_MySQL数据移植中的乱码问题

    mysql移植含有中文的数据时,很容易出现乱码问题.很多是在从mysql4.x向mysql5.x移植的时候出现.mysql的缺省字符集是latin1,在使用mysql4.x的时候,很多人都是用的lat ...

  10. powerbuilder freeform只显示一条数据的问题

    问题:pb中的freeform在显示数据时,明明数据库中有多条数据,可是显示在freeform中却只有一条. 在网上查了很多很多资料,怎么说的都有,但就是没一个说的是对的,真是让人无奈.网上说的最多的 ...

最新文章

  1. Parcelable与Serializable的比较
  2. 网站颜色搭配的好网站。
  3. JavaWeb:JDBC之数据库连接池
  4. window下eclipse +cdt+cygwin做C,C++开发环境搭建 (转自:http://blog.csdn.net/thinkandchange/article/details/7935)
  5. 分布式文件系统研究-fastDSF文件上传和下载流程
  6. java实现米和厘米比较好_java如何根据实际经、纬度和已知经、纬度做对比,计算出具体偏差米数。(以米为单位)...
  7. 疫情中该如何保证高效远程办公(1)-员工到底是在家办公,还是在家躺着??
  8. 服务器找不到硬盘如何解决方案,Linux云服务器磁盘不见了?解决方案在这里
  9. 《Web Load Testing For Dummie》读书笔记
  10. 换工位解决ssh 卡住的背后
  11. Photoshop1:入门实用技巧
  12. android百度地图获取定位信息吗,android使用百度地圖定位(獲取當前經緯度和地址信息)...
  13. mysql客户端汉化_【原创】Mysql客户端如何处理中文
  14. CNN网络实现垃圾分类
  15. php m3u8转mp4
  16. java一些必会算法(转自落尘曦的博客:http://blog.csdn.net/qq_23994787。 )
  17. python中三目运算符、推导式 ## 17
  18. Ubuntu16.04 打不开文件夹解决办法 | killall nautilus的原理 |nautilus命令快速打开文件
  19. Vue3通透教程【四】Vue3组合API初体验
  20. Java 回升!月薪 25K 的无名公司是谁?75 万招聘数据揭晓谁最大方!

热门文章

  1. promise的理解和使用-尚硅谷教程笔记
  2. npm install -g @vue/cli时 -4048 npm ERR! Error: EPERM: operation not permitted, lstat报错的几种解决方案
  3. git学习笔记-(4-git对象)
  4. matlab导入arcgis中国边界图,【干货】ArcGIS提取影像边界的几种方法
  5. mysql md5全库比较_关于mysql搭建亿级cmd5数据库,毫秒级查询(完整过程)
  6. NO.3 寻找数组主要元素
  7. MySQL(4)-----DML数据库操作(下)
  8. Codeforces Round #558 Div.2 - C2 - Power Transmission (Hard Edition)
  9. 毕设一:python 爬取苏宁的商品评论
  10. android-async-http框架之与网络进行数据交互