count(*)
如果有个页面经常要显示交易系统的操作记录总数,如何计数?
- 如果用redis来保存这个表的总行数,可能存在一些问题,比如在数据表中插入一行数据后,准备将redis中的计数+1时,redis异常重启了,那刚刚这个+1的操作就丢失了,这个场景下是有解的,就是redis异常重启后,到数据库里单独执行一次 count(*) 来获取真实的行数,并写回到redis即可,由于异常重启不是经常出现的状况,所以这一次全表扫描的成本是可以接受的。但还有个问题是,redis所计数的值是不精确的,比如在执行新增记录逻辑时,先写数据库,再改redis计数,读的时候先读redis,再读数据表中的记录,此时可能出现:插入一行数据后,还没来得及给redis中的计数+1,就读了redis中的计数和数据表中的记录。
- 所以可以将这个计数放到数据库中用单独的一张计数表进行记录。InnoDB支持崩溃后数据的恢复,不会让数据丢失,并且由于InnoDB支持事务,所以可以避免redis中的不精确问题:比如先插入数据,再更新计数,如果在这中间进行了读的操作,由于前面的更新事务还没提交,更新的操作对读操作是不可见的,所以读到的数据还是未插入前的数据。
count(1) 和 count(*)
- count(1) 会遍历整张表,但不取值,按行进行累加
- count(*) 也不取值, InnoDB 专门对其进行了优化
- 查找效率方面,两者差不多,尽量使用 count(*)