[root@localhost][test]: show create table t3\G*************************** 1. row ***************************Table: t3Create Table: CREATE TABLE `t3` (`id` int(11) DEFAULT NULL,`num` int(11) DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb41 row in set (0.05 sec)[root@localhost][test]: insert into t3 values(1,2),(2,3);Query OK, 2 rows affected (0.07 sec)Records: 2 Duplicates: 0 Warnings: 0[root@localhost][test]: insert into t3 (num) values(4);Query OK, 1 row affected (0.01 sec)[root@localhost][test]: select count(1),count(*),count(id) from t3;+----------+----------+-----------+| count(1) | count(*) | count(id) |+----------+----------+-----------+| 3 | 3 | 2 |+----------+----------+-----------+
count(1)代表总记录数,与,count(*)一致 count(id) 代表非空记录数
当然还有count(主键)
对于性能来说:
对于count(主键id)来说, InnoDB引擎会遍历整张表,把每一行的id值都取出来,返回给server层。 server层拿到id后,判断是不可能为空的,就按行累加。
对于count(1)来说, InnoDB引擎遍历整张表,但不取值。 server层对于返回的每一行,放一个数字“1”进去,判断是不可能为空的,按行累加。
单看这两个用法的差别的话,你能对比出来, count(1)执行得要比count(主键id)快。因为从引擎返回id会涉及到解析数据行,以及拷贝字段值的操作。
对于count(字段)来说:
1. 如果这个“字段”是定义为not null的话,一行行地从记录里面读出这个字段,判断不能为null,按行累加;
2. 如果这个“字段”定义允许为null,那么执行的时候,判断到有可能是null,还要把值取出来再判断一下,不是null才累加。
也就是前面的第一条原则, server层要什么字段, InnoDB就返回什么字段。
但是count(*)是例外,并不会把全部字段取出来,而是专门做了优化,不取值。 count(*)肯定不是null,按行累加。
总结:按照效率排序的话, count(字段)<count(主键id)<count(1)≈count(),所以建议,尽量使用count()
对于频繁使用count(*)的表,建议创建一张计数表,将计数操作跟insert和delete放在同一个事务里,考虑到并发行锁的争用,将计数表修改尽量放在commit的前一步
