SQL 中 Count(*) 与 Count(1) 有何不同

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(*) 快,但是并没有给出什么实质性数据,总体上来说其效率是几乎一致的,参考阿里的编码规范:

《Java开发手册》v1.5.0 华山版中规定:

【强制】不要使用 count(列名)count(常量) 来替代 count(*)count(*)SQL92 定义的标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。

说明:count(*) 会统计值为 NULL 的行,而 count(列名) 不会统计此列为 NULL 值的行。

综上所述,统计完整行数还是使用 count(*) ,至于具体到某一列的什么去重非空的统计,那肯定是 count(column) 搭配 distinctis not null 使用

posted @ 2021-12-02 14:00  他是医你的药  阅读(257)  评论(0编辑  收藏  举报