count查询优化

  这里讨论的count查询优化是针对INNODB存储引擎的!

  首先抛出一个问题

  count(*)、count(主键)、count(1)、count(字段)它们四者之间的效率如何排序?

  在我们以往的工作经验中,总是听到说不要使用count(*),因为 * 号代表了所有列,计算会更慢,然后就推荐了使用count(主键)。但事实真的是这样吗?

笔者在最近的学习中也才认识到这个错误。

  这四者正确的排序应该是这样的:

count(1) > count(*) > count(主键) > count(字段)

  笔者特意在一张只有主键索引的1千万条数据的表中做了测试,以下是测试的结果:

       

 

   这张图的数据不是偶然的,笔者针对每种查询执行了多次,结果不会有太大的变化,验证了以上排序的正确性。

  count()的作用

  count()是一个特殊的函数,有两种非常不同的作用:它可以统计某个列值的数量,也可以统计行数。在统计列值时要求列值

是非空的(不统计NULL)。如果在count()的括号中指定了列或者列的表达式,则统计的就是这个表达式有值的结果数,而不是NULL。

  count()的另一个作用是统计结果集的行数。当MYSQL确认括号内的表达式值不可能为空时,实际上就是在统计行数。最简单的就

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

所有的行数。

  最常见的一个错误就是,在括号内指定了一个列却希望统计结果集的行数。如果希望知道的是结果集的行数,最好使用COUNT(*),

这样写意义清晰,性能也会很好。

  count()的另一个优化

  业务代码中,有这样一个需求,需要根据一个或多个条件,查询是否存在记录,不关心有多少条记录。普遍的SQL及代码写法如下:

SELECT count(*) FROM T WHERE a = 1 AND b = 2

  java写法如下

Integer exist = xxDao.existXxxxByXxx(params);
if ( exist != NULL ) {
  //当存在时,执行这里的代码
} else {
  //当不存在时,执行这里的代码
}

  对于此处的select count(*),并不需求将符合条件的条数都统计出来,可以优化成如下的SQL:

SELECT count(*) FROM T WHERE a = 1 AND b = 2 LIMIT 1

  这里相比上面的SQL多了LIMIT关键字,在MYSQL中,执行器执行到LIMIT关键字,只要满足LIMIT的条数,存储引擎就不会再对数据文件

进行检索,直接返回,所以这里只需要检索到1条之后就返回结果,效率可想而知快了不少!

posted @ 2020-11-17 22:01  寻找的路上  阅读(1018)  评论(0编辑  收藏  举报