一些特殊情况:
- 有索引时:如果查询使用了索引,且查询的列在索引中,
COUNT(某一列)
可能在某些情况下会比较快,因为数据库只需要扫描索引,而不需要扫描整个表。 - 有 NULL 值时:
COUNT(某一列)
可能会因为 NULL 值的过滤而表现出与其他方法不同的性能特征。 WHERE
子句:无论是COUNT(*)
,COUNT(1)
, 还是COUNT(某一列)
,它们在有WHERE
子句时,都会受限于条件的筛选,性能可能会受到查询条件的影响。
结论:
- 对于大多数查询,推荐使用
COUNT(*)
,因为它通常是数据库最优化的选择。 COUNT(1)
性能与COUNT(*)
基本相同,因此可以作为备选。COUNT(某一列)
由于需要检查列值是否为 NULL,通常会稍微慢一些,特别是在数据中有大量 NULL 时。
一 介绍
1、COUNT(*):
这个表达式会计算表中的所有行,包括那些值为NULL的行。它不考虑列的选择,直接统计整个表的行数。
MySQL官网[1]中有说明:InnoDB通过遍历最小的可用二级索引来处理SELECT COUNT(*)语句,除非索引或优化器提示优化器使用不同的索引。如果二级索引不存在,InnoDB通过扫描聚簇索引来处理SELECT COUNT(*)语句。
为什么要采用遍历最小的可用二级索引,而不是直接选聚簇索引?
因为二级索引不存储具体数据,相比聚簇索引占用空间小,遍历的I/O效率更高。
2、COUNT(1):
这是一个优化过的计数方式,实际上并不计算任何列的值,而是把“1”作为一个常量来对待,统计的是满足条件的行数。这种方式避免了访问表的具体列,理论上可以提高效率,尤其是在列值可为空的情况下。
MySQL官网[1]中有说明:InnoDB处理SELECT COUNT(*)和SELECT COUNT(1)操作的方式相同。
3、COUNT(某一列):
这个表达式统计的是指定列中非NULL值的数量。如果该列有NULL值,那么这些行不会被计入总数中。
二 区别
1、数据处理范围:
COUNT(*)
包括了所有行,无论列值是否为NULL;COUNT(1)
同样统计所有行,因为它计数的是恒定的1,不关心行数据的实际内容;而COUNT(某一列)
只统计该列非NULL值的行数。
2、性能影响因素:
由于COUNT(*)
和COUNT(1)
不需要访问实际的数据行(特别是当索引可以覆盖查询需求时),它们的执行效率可能高于COUNT(某一列)
,特别是当该列含有大量NULL值时。
3、应用场景:
如果你需要统计表的所有行数,包括那些具有NULL值的行,应使用COUNT(*)
或COUNT(1)
。若你需要统计特定列的非NULL值数量,则应使用COUNT(某一列)
。
三 性能比较
1、在MySQL中,COUNT(*)
和COUNT(1)
的性能差异微乎其微,甚至可以认为是等价的。在MySQL官网中,明确指出InnoDB引擎中两语句性能一致[1]。原文如下:
InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.
2、相比之下,COUNT(某一列)
的性能取决于该列的数据分布,特别是NULL值的比例。如果该列包含大量NULL值,且查询优化器无法有效利用索引,那么它的执行效率可能会低于前两者。其中COUNT(主键)相比COUNT(普通列)的性能要好。
3、实际性能还受到数据库索引、表结构、数据量、以及数据库管理系统具体实现等因素的影响。因此,在特定场景下,需进行实际测试。
四 结语
总的来说,COUNT(*)
和COUNT(1)
在统计全表行数时非常相似,且在多数情况下性能相当,推荐在不需要考虑特定列的NULL值时使用。而COUNT(某一列)
则适用于需要精确统计某列非NULL值数量的场景。在考虑性能优化时,了解并利用数据库的特定优化特性和执行计划分析工具,可以帮助做出更合适的选择。