1. [root@localhost][test]: show create table t3\G
    2. *************************** 1. row ***************************
    3. Table: t3
    4. Create Table: CREATE TABLE `t3` (
    5. `id` int(11) DEFAULT NULL,
    6. `num` int(11) DEFAULT NULL
    7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
    8. 1 row in set (0.05 sec)
    9. [root@localhost][test]: insert into t3 values(1,2),(2,3);
    10. Query OK, 2 rows affected (0.07 sec)
    11. Records: 2 Duplicates: 0 Warnings: 0
    12. [root@localhost][test]: insert into t3 (num) values(4);
    13. Query OK, 1 row affected (0.01 sec)
    14. [root@localhost][test]: select count(1),count(*),count(id) from t3;
    15. +----------+----------+-----------+
    16. | count(1) | count(*) | count(id) |
    17. +----------+----------+-----------+
    18. | 3 | 3 | 2 |
    19. +----------+----------+-----------+

    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的前一步