天天看点

mysql中count(x)到底慢不慢

总结

MyISAM 表不支持事务,但是count(*) 很快,因为他直接记录了一个总数

MyISAM在统计表的总行数的时候会很快,但是有个大前提,不能加有任何WHERE条件。这是因为:MyISAM对于表的行数做了优化,具体做法是有一个变量存储了表的行数,如果查询条件没有WHERE条件则是查询表中一共有多少条数据,MyISAM可以做到迅速返回,所以也解释了如果加WHERE条件,则该优化就不起作用了。细心的同学会发现,innodb的表也有这么一个存储了表行数的变量,但是很遗憾这个值是一个估计值,没有什么实际意义。

show table status  虽然很快,但是不精准

InnoDB 表直接 count(*) 会遍历全表,虽然结果准确,但是性能很差

count(*)   count(id)  count(1)  count(字段) 性能对比

count的定义:

COUNT()有两个非常不同的作用:

1.它可以统计某个列值的数量,也可以统计行数。在统计列值时要求列值是非空的(不统计NULL)。如果在COUNT()的括号中定了列或者列表达式,则统计的就是这个表达式有值的结果数。

2.COUNT()的另一个作用是统计结果集的行数。当MySQL确认括号内的表达式值不可能为空时,实际上就是在统计行数。最简单的就是当我们使用COUNT(*)的时候,这种情况下通配符*并不像我们猜想的那样扩展成所有的列,实际上,他会忽略所有列而直接统计所有的行数“

count(id) InnoDB会遍历整个表,把每一行的id都取出来,返回给server层。server层拿到id后,判断是不可能为空的,就按行累加

count(1) InnoDB会遍历整个表,不取值。server层放一个数字1进去,判断是不可能为空的,按行累加

所以:count(1) 比 count(id) 快,因为从引擎返回id会涉及到解析数据,copy字段值等操作

count(字段)来说:

  1. 如果这个字段是定义为not null的话,一行一行读取这个字段,判断不能为null,按行累加
  2. 如果这个字段定义为允许null,判断到有可能为null,还要把值取出来再判断一下,不是null才累加

count(*) 是个例外,并不会把全部字段都取出来,而是专门做了优化,不取值,count(*)肯定不是null,按行累加

结论(性能从高到低):

count(*) > count(1) >  count(id) > count(字段)

大数据量的mis系统,列表页分页如何读取总数?

  1. 写死总数,mis后台内部使用,本来精度要求就不高,大部分用搜索就可以满足了 ,简单快捷
  2. 单独redis计数,定时脚本修正数据 ,简单,存在部分误差
  3. mysql统计表,通过事务保证一致性,性能差,维护复杂度高

分页如何优化

  1. 改为 id>xxx  limit m 根据排序条件建立索引,记录开始的位置
  2. 利用覆盖索引,减少无效回表。