Count(*) Count(1) 与 Count(column)
在学习 SQL 的时候,不止一次被提醒过统计记录数时需要使用 Count(*) 而不是 Count(column),因为 Count(*) 会统计值为 NULL 的记录,而最近在看项目代码的时候,我发现某个 Mapper 文件中使用较多的居然是 Count(1),因此来记录一下这三种方式的优缺!
NULL 值统计情况
新建一张表,仅有一列,添加两条 NULL 记录、两条有值记录
分别使用 count(*) count(1) count(id)
来进行查询,结果如下:
SELECT count(*),count(1),count(id) FROM `count_demo`
--
count(*) count(1) count(id)
4 4 2
很显然,从最终执行效果来看,count(1)
和 count(*)
统计了 NULL,count(id)
自然还是不计算 NULL 值。
索引执行情况
这个时候我们又需要另外一张表,其包含多个列,含主键 SId
CREATE TABLE `student` (
`SId` varchar(10) NOT NULL,
`Sname` varchar(10) DEFAULT NULL,
`Sage` datetime DEFAULT NULL,
`Ssex` varchar(10) DEFAULT NULL,
PRIMARY KEY (`SId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
查看执行计划
EXPLAIN
SELECT count(1) FROM `student`;
-- type = index
EXPLAIN
SELECT count(*) FROM student;
-- type = index
EXPLAIN
SELECT count(SId) FROM student;
-- type = index
EXPLAIN
SELECT count(Sage) FROM student;
-- type = all
所以,除了特地 count 不包含索引的列之外,在表中有索引的情况下,count(*)
和 count(1)
都是会走索引的。
总结
从使用效果来看:
count(*)
包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为 NULL 的记录,且在表中有索引的情况下会扫描索引count(1)
包括了忽略所有列,用 1 代表代码行,在统计结果的时候,不会忽略列值为 NULL 的记录,且在表中有索引的情况下会扫描索引count(column)
只包括列名那一列,在统计结果的时候,会忽略列值为 NULL 的计数,是否扫描索引与该列是否添加了索引有关
至于使用效率来看,大多数博客说在数据量大的时候 count(1)
会比 count(*)
快,但是并没有给出什么实质性数据,总体上来说其效率是几乎一致的,参考阿里的编码规范:
【强制】不要使用
count(列名)
或count(常量)
来替代count(*)
,count(*)
是 SQL92 定义的标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。说明:count(*) 会统计值为 NULL 的行,而 count(列名) 不会统计此列为 NULL 值的行。
综上所述,统计完整行数还是使用 count(*)
,至于具体到某一列的什么去重非空的统计,那肯定是 count(column)
搭配 distinct
和 is not null
使用