mysql not in优化_mysql高级(三)——sql调优

9c1b400897891323501fb5a6b26a2c2a.png

原文:https://blog.csdn.net/u011702633/article/details/82726547

小表驱动大表

使用in的sql:select * from A where id in (select id from B)

等价于:

for select id from Bfor select * from A where A.id = B.id

当B表的数据小于A表的数据集时,用in

使用exists的sql:select * from A where exists (select 1 from B where B.id=A.id)

等价于:

for select id from Afor select * from B where B.id = A.id

当A表的数据小于B表的数据集时,用exists

EXISTS:

select …from table where exists (subquery)可以理解为:将主查询的数据。放到子查询中做条件验证,根据验证结果(true or false)来决定主查询的数据是否得以保留

提示:

  • exists(subquery)只返回true或者false,因此子查询的select *可以使select 1或其他,实际执行时候会忽略掉select清单,因此没有区别

  • exists子查询的实际执行过程可能经历了优化而不是我们理解上的逐条对比,如果担忧效率问题,可进行实际检验以确认效率是否有问题

  • exists子查询往往也可以用条件表达式、其他子查询或者join来代替

索引排序问题(order by和group by类似)

索引的作用,除了查找还有一个就是排序

699cfb7eaaa6909ab242e3a062a67568.png

可以看到Extra里有一个Using filesort用来排序,mysql里面排序的有filesort和索引自带的排序,当然我们建立的有复合索引,如果能用到索引的排序,那么效率将会提升很多,下面我们来看看怎么用上索引排序

895c9b9f576b8bef370105ea0b93efc8.png

4ce953af9860ac8c536c6249fa45b33b.png

54f814e0c4b0f88a156035904a64ab6c.png

结论:where后面跟的索引和order by后面的排序字段满足最佳最前缀原则,并且也是范围之后就失效

oder by后面的子段自己满足左前缀原则也可以

fbb6c52c5e701f5c1fd6648a8cb07411.png

11e34f244c082150f1542737e943ddb4.png

c41cd0a1470840bd869d69d9ef8438dc.png

结论:order by后面的字段可以不考虑where用到的索引,自己满足做前缀法则来使用复合索引即可用到索引排序,那么第三个为什么没用到呢?当用到name asc的时候,组合索引用的是升序,但是后面的age来也用这个索引排序的时候发现是升序用不了,就产生了个filesort的降序排序。证明如下:

86fe831027686f3b41afbea4a35442fe.png

第一个name满足做前缀来使用复合索引的升序排序,第二个name也满足做前缀法则,使用了复合索引的降序排序,这样其实用了两次索引,一次用索引的升序,一次用降序

64063352822f43bbd85dfa054adcb346.png

42986a61110ddbf637fe02e99a0be869.png

156094aad9173257cad3b3e3da934eda.png

这两个出现的原因就是,前面where已经创建了一个索引,age>20导致索引age后面的pos失效,但是order by从age开始的排序还是可以用的;但是order by pos失效(因为pos失效了),索引图二产生了filesort;图三,order by age pos虽然pos失效了,但是再从age开始,pos也又可以用了

结论:我们得出首先where后面如果用上索引会开一个索引来查找,下一个字段如果满足条件就接着用这个索引来查找;到了order by后面的字段如果能和where后的字段满足做前缀法则就可以接着用where后面开的的索引来进行排序;否则就自己在开一个(升序或者降序)索引来排序,如果order by有多个字段也是一样的,能用到前面字段开的索引就用,否则自己就在开一个

98684bd7d19b3cb67a9d834e5e2757a7.png

sql慢查询分析

慢查询日志开启方法一:

在配置文件my.cnf或my.ini中在[mysqld]一行下面加入两个配置参数log-slow-queries=/data/mysqldata/slow-query.loglong_query_time=2注:log-slow-queries参数为慢查询日志存放的位置,一般这个目录要有mysql的运行帐号的可写权限,一般都将这个目录设置为mysql的数据存放目录;long_query_time=2中的2表示查询超过两秒才记录;在my.cnf或者my.ini中添加log-queries-not-using-indexes参数,表示记录下没有使用索引的查询。log-slow-queries=/data/mysqldata/slow-query.loglong_query_time=10log-queries-not-using-indexes

慢查询日志开启方法二:

我们可以通过命令行设置变量来即时启动慢日志查询。由下图可知慢日志没有打开,slow_launch_time=# 表示如果建立线程花费了比这个值更长的时间,slow_launch_threads 计数器将增加

66390bba44dfc136cd8fb8f924b2cbd0.png

设置慢日志开启

8b09ff920e22b84fa5b983f7b6775ebb.png

MySQL后可以查询long_query_time 的值

c625c0c8aabcf7d8ff45fddd5826ec7c.png

为了方便测试,可以将修改慢查询时间为5秒

7e3ccfd5f8bbeeeb5c7594ad6b2400b2.png

执行select sleep(6)睡眠6秒,在慢查询日志文件下面就有一条记录了

当然mysql自带一个分析工具,具体命令见下:

17b7a7d4c970a76ed75e6685a8b1a69f.png

cfd4d991be6f832c7be004ef0239439a.png

show profile

  • 查看命令:show variables like ‘profiling%’;默认关闭,使用前需要开启;

  • 开启命令:set profiling=on;

  • 开启之后,运行sql会被mysql记录

  • 查看执行sql记录结果(带有sql的id和执行时间):Show profiles;

  • 诊断sql :show profile cpu, block io for query 问题sql的id;

日常开发需要注意的结论:

converting HEAP to MyISAM :查询结果太大,内存都不够用了,往磁盘上搬了;

creating tmp table :创建临时表,拷贝数据到临时表,然后再删除;

copying to tmp table on disk :把内存中临时表复制到磁盘,危险!!!

locked

注:以上四个中若出现一个或多个,表示sql 语句 必须优化。

输出内容里面的字段表示含义:

  • ALL: 显示所有的开销信息

  • BLOCK IO :显示块IO相关开销

  • CONTEXT SWITCHS: 上下文切换相关开销

  • CPU : 显示cpu 相关开销

  • IPC: 显示发送和接收相关开销

  • MEMORY:显示内存相关开销

  • PAGE FAULTS:显示页面错误相关开销信息

  • SOURCE :显示和Source_function ,Source_file,Source_line 相关的开销信息

  • SWAPS:显示交换次数相关的开销信息

  • Status :sql 语句执行的状态

  • Duration: sql 执行过程中每一个步骤的耗时

  • CPU_user: 当前用户占有的cpu

  • CPU_system: 系统占有的cpu

  • Block_ops_in : I/O 输入

  • Block_ops_out : I/O 输出

c8d3be607aa803160e50c64a6c387dee.png 526ba79f795ea3d9eebceb446b21ad87.gif 183a2e63af32b957387795afd5531aad.png f28ee9d885b5069abc768706384cc8ef.gif想要获取学习实战、高并发、架构 、笔试面试资料请扫码咨询+薇薇微信
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值