count() 函数相关知识
不同的 count 用法对比
count() 的语义:count() 是一个聚合函数,对于返回的结果集,一行行地判断,如果 count 函数的参数不是 NULL,累计值就加 1,否则不加。
所以,count(*)、count(主键 id) 和 count(1) 都表示返回满足条件的结果集的总行数;而 count(字段)表示返回条件的数据行里,参数字段不为 NULL 的总个数。
提炼:count(字段) 统计的是 字段不为 NULL 的结果总数;其余情况下统计的是全部结果(无论字段是否为 NULL)。
至于分析性能差别的时候,你可以记住这么几个原则:
- server 层要什么就给什么;
- InnoDB 只给必要的值;
- 现在的优化器只优化了 count(*) 的语义为 “取行数”,其他“显而易见”的优化并没有做。
下面逐个解释:
对于 count(主键)来说,InnoDB 引擎会遍历整张表,把每一行的 id 值都取出来,返回给 server 层。server 层拿到 id 之后,判断是不可能为空的,就按行累加。
对于 count(1) 来说, InnoDB 引擎遍历整张表,**但不取值。**server 层对于返回的每一行,放一个数字“1”进去,判断是不可能为空的,按行累加。
对于 count(字段) 来说:
- 如果这个“字段”是定义为 not null 的话,一行行的从记录里面读出这个字段,判断不能为 null,按行累加。
- 如果这个“字段”定义允许为 null,那么执行的时候,判断有可能是 null,还要把取值出来再判断一下,不是 null 才累加。
但 count() 是个例外,**并不会把全部字段取出来,而是专门做了优化,不取值。**count()肯定不是 null,按行累加。
结论:按照效率排序的话,count(字段)<count(主键 id)<count(1)≈count(),所以我建议你,尽量使用 count()。
🌰: 我创建一张 user 表,表里面的属性有 id(主键)、username、password、birthday。图中可以看到其中 id=13 这一条记录的 username = NULL。 执行 SQL 语句:
select count(*), count(id), count(1), count(username) from user;
查看结果:
|