SQL高级优化

优化争议无数的count()

      

统计列与统计行?

  COUNT()是一个特殊的函数,有两种不同的作用,它可以统计某个列值的数量,也可以统计行数。

  在统计列值的时候要求列值是非空的,也就是不统计null。

  当我们统计行的时候,常见的是COUNT(*),这种情况下,通配符*并不会像我们猜想的那样扩展成所有的列,实际上,它会忽略所有的列而直接统计所有的行数

解密MyiSAM的‘快’

  这是一个容易产生误解的事情:MyiSAM的count()函数总是非常快。

  不过它是有前提条件的,条件是没有任何where条件的count(*)才非常快,因为此时无须实际的去计算表的行数,mysql可以利用存储引擎的特性直接获得这个值,如果mysql知道某列不可能有null值,那么mysql内部会将count(列)表达式优化为count(*)。

  当统计带有where条件的查询,那么mysql的count()和其他存储引擎就没有什么不同了。

COUNT(1)、COUNT(*)、COUNT(列)

  (先提前申明,本人是在innodb库里做的实验。)

扫描二维码关注公众号,回复: 5414582 查看本文章

  1.count(1)和count(*)直接就是统计主键,他们两个的效率是一样的。如果删除主键,他们都走全表扫描。

  2.如果count(列)中的字段是索引的话,count(列)和count(*)一样快,否则count(列)走全表扫描。

      3.count()可以用case when 语句来进行进一步的筛选,不过也是看字段

优化order by 语句

MySQL的排序方式

  优化order by语句就不得不了解mysql的排序方式。

  1.第一种通过有序索引返回数据,这种方式的extra显示为Using Index,不需要额外的排序,操作效率较高。

  2.第二种是对返回的数据进行排序,也就是通常看到的Using filesort,filesort是通过相应的排序算法,将数据放在sort_buffer_size系统变量设置的内存排序区中进行排序,如果内存装载不下,它就会将磁盘上的数据进行分块,再对各个数据块进行排序,然后将各个块合并成有序的结果集。

filesort的优化

  了解了MySQL排序的方式,优化目标就清晰了:尽量减少额外的排序,通过索引直接返回有序数据。where条件和order by使用相同的索引。

  1.创建合适的索引减少filesort的出现。

  2.查询时尽量只使用必要的字段,select 具体字段的名称,而不是select * 选择所有字段,这样可以减少排序区的使用,提高SQL性能

优化group by 语句

为什么order by后面不能跟group by ?

  事实上,MySQL在所有的group by 后面隐式的加了order by ,也就是说group by语句的结果会默认进行排序。

  如果你要在order by后面加group by ,那结果执行的SQL是不是这样:select * from tb order by ... group by ... order by ... ? 这不是搞笑吗?

禁止排序

  既然知道问题了,那么就容易优化了,如果查询包括group by但又不关心结果集的顺序,而这种默认排序又导致了需要文件排序,则可以指定order by null 禁止排序。

例如:

select * from tb group by name order by null;

优化limit 分页

  一个非常常见又非常头痛的场景:‘limit 1000,20’。

  这时MySQL需要查询1020条记录然后只返回最后20条,前面的1000条都将被抛弃,这样的代价非常高。如果所有页面的访问频率都相同,那么这样的查询平均需要访问半个表的数据。

第一种思路 在索引上分页

  在索引上完成分页操作,最后根据主键关联回原表查询所需要的其他列的内容。

例如:

SELECT * FROM tb_user LIMIT 1000,10

可以优化成这样:

SELECT * FROM tb_user u 
INNER JOIN (SELECT id FROM tb_user LIMIT 1000,10) AS b ON b.id=u.id

第二种思路 将limit转换成位置查询

这种思路需要加一个参数来辅助,标记分页的开始位置:

SELECT * FROM tb_user WHERE id > 1000 LIMIT 10

优化子查询

子查询,也就是查询中有查询,常见的是where后面跟一个括号里面又是一条查询sql

  尽可能的使用join关联查询来代替子查询。

  当然 这不是绝对的,比如某些非常简单的子查询就比关联查询效率高,事实效果如何还要看执行计划。

  只能说大部分的子查询都可以优化成Join关联查询。

改变执行计划

提高索引优先级

  use index 可以让MySQL去参考指定的索引,但是无法强制MySQL去使用这个索引,当MySQL觉得这个索引效率太差,它宁愿去走全表扫描。。。

SELECT * FROM tb_user USE INDEX (user_name)

  注意:必须是索引,不能是普通字段,(亲测主键也不行)。

忽略索引

  ignore index 可以让MySQL忽略一个索引

SELECT * FROM tb_user IGNORE INDEX (user_name) WHERE user_name="张学友" 

强制使用索引

  force index 使用了force index 之后 尽管效率非常低,MySQL也会照你的话去执行

SELECT * FROM tb_user FORCE INDEX (user_name) WHERE user_name="张学友" 

查看执行计划时建议依次观察以下几个要点:

  1.SQL内部的执行顺序。
  2.查看select的查询类型。
  3.实际有没有使用索引。
  4.Extra描述信息

持续更新中。。。。

猜你喜欢

转载自blog.csdn.net/weixin_41624046/article/details/84788598
今日推荐