没有特殊说明,以下均是针对哦InnoDB引擎的说明
实现方式
不同的MySQL引擎的实现方式不同
- MyISAM引擎把一个表的总行数存在了磁盘上,因此执行无条件count(*)的时候会直接返回这个数,效率很高
InnoDB引擎由于有MVCC机制,针对不同的视图,放回的条数不同,需要根据扫描到行数进行计数,这就导致InnoDB引擎的count()操作当数据量增大的时候效率会变慢
单独对总数进行缓存
对于需要查询总数的业务场景,可以将总数计数放到缓存中单独存储,这样逻辑上就应该有两步操作:
插入记录
-
数据一致性问题
假设将计数放到Redis中
可能会有缓存计数丢失问题,假设Redis的缓存还没有持久化就异常重启了,Redis重启后就丢失了一次+1操作
- 这个问题可以通过每次Redis重启的时候从数据库中取一次真实值,因为Redis也不会经常重启,偶尔一次查询慢也没问题
假设在执行insert之后,还没有更新Redis计数,查询时查询到了insert的记录,但是总数还是insert之前的,反过来也一样
count(主键):InnoDB引擎会遍历整张表,把每一行的主键值都取出来,返回给server层,server层拿到id后,判断是不可能为空的,计数加一
- count(字段):
- 如果该字段定义为not null,判断到不能为null,就一行行的读出这个字段来按行累加计数
- 如果该字段定义为null,判断到可以为null,读出来字段后,还要把取出来的值再判断一下(猜测这一步是在server层完成的,InnoDB只负责读数据),不是null才累加
- count(1):InnoDB变量整张表,但不取值,server层对于返回的每一行,放一个数字“1”进去,判断是不可能为空的,按行累加
- count():并不会把全部字段取出来,而是专门做了优化,不取值,count()肯定不是null,按行累加
count(1)执行效率要比count(主键)快,因为count(主键)涉及数据的读取解析,而count(字段)比count(主键)效率要低。
