MySQL 查询优化

99封情书 提交于 2020-03-14 09:41:14

1、MySQL 查询统计数据表行数三种方式:select count(*) 、select count(1) 、select count(具体字段),三者查询效率是怎么样的呢?

解答:

在MySQL InnoDB 存储引擎中,count(*) 和count(*) 都是对所有结果进行count。如果有where 子句,则是对所有筛选条件的数据行进行统计;如果没有where子句,则是对数据表的数据行数进行统计。

因此count(*) 和 count(1) 本质上并没有区别,执行的复杂度都是O(N),也就是采用全表扫描,进行循环+计数的方式进行统计。

如果是MySQL MyISAM 存储引擎,统计数据表的行数只需要O(1)的复杂度,这是因为每张MyISAM的数据表都有一个meta信息存储了row_count值,而一致性则由表级锁来保证,因为InnoDB支持事务,采用行级锁和MVCC机制,所以无法像MyISAM一样,只维护一个row_count变量,因此采用扫描全表,进行循环+计数的方式来完成统计;

在执行过程中,count(*) 和 count(1)执行时间略有差别,不过效率可以基本看成是相等的。

一般情况,三者的执行效率count(1) = count(*) >count(字段)。我们尽量使用count(*),当然如果你知道你要统计的是某个字段的非空数据行数,则另当别论,毕竟比较执行效率的前提是结果一样才可以。

如果统计count(*),尽量在数据表上建立二级索引,系统会自动采用key_len小的二级索引,这样当我们使用select count(*) 的时候效率会提升。

 

2、limit 关键词是最后执行的,如果只有一条结果,limit 还有用吗?

解答:

如果你确认结果集只有一条,加上limit 1,当找到一条结果的时候就不会继续扫描了,这样会加快查询速度,这里指的查询优化针对的是会扫描全表的sql语句,如果数据表已经对字段建立了唯一索引,那么可以通过索引进行查询,不会全表扫描的话,就不需要加limit了。

 

3、可以理解在where 条件字段上加索引,但是为什么在order by 字段上还要加索引呢?这个时候已经通过where条件过滤得到了数据,已经不需要再筛选过滤数据了,只需要根据字段排序就好了。

解答:

在MySQL中支持两种排序方式,分别是FileSort 和 Index 排序。在Index中,索引可以保证数据的有序性,不需要再进行排序,效率更高。filesort 排序则一般再内存中进行排序,占用cpu较多,如果待排结果较大,会产生临时文件I/O到磁盘进行排序的情况,效率较低。

所以使用Order by 子句时,应该尽量使用Index 排序,避免使用File Sort排序,当然你可以使用explain 来查看执行计划。

优化建议:

1)SQL中,可以在where 子句和order by 子句中使用索引,目的在where子句中避免全表扫描,在order by子句避免使用File sort排序,当然某些情况下全表扫描,或者filesort排序不一定比索引慢。

2)尽量使用index 完成order by排序,如果where 和order by 后面是相同的列就使用单列索引,不是则使用联合索引。

3)无法使用index 时,需要对filesort方式进行调优。

 

4、order by 是对分的组排序还是对分组中的记录排序呢?

解答:

order by 就是对记录进行排序,如果你在order by 前面用了group by,实际上这是一种分组的聚合方式,已经把一组的数据聚合成为了一条记录,再进行排序的时候,相对于对分的组进行了排序。

 

5、一条完整的select 语句内部的执行顺序是这样的:

1、from 子句组装数据(包括通过on进行连接);

2、where 子句进行条件筛选;

3、group by 分组;

4、使用聚合函数进行计算;

5、having 筛选分组;

6、计算所有的表达式;

7、select 的字段;

8、order by 排序;

9、limit 筛选。

 

6、不太理解哪种情况下应该使用exists,哪种情况使用in。选择的标准是看能否使用表的索引吗?

解答:

索引是个前提,其实选择与否还是要看表的大小,你可以将选择的标准理解为小表驱动大表,这种方式是效率最高的。

比如:

SELECT * FROM A WHERE cc IN (SELECT cc FROM B)
SELECT * FROM A WHERE EXISTS (SELECT cc FROM B WHERE B.cc=A.cc)

  当A<B时,用 EXISTS。因为 EXISTS 的实现,相当于外表循环,实现的逻辑类似于:

for i in A
  for j in B
    if j.cc == i.cc then ...

 当B<A时,用in,因为实现的逻辑类似于:

for i in B
    for j in A
        if j.cc == i.cc then    

 哪个表小就用哪个表来驱动,A表小就用exists,B表小就用in 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!