MySQL的COUNT(1)、COUNT(*)与COUNT(列名)还浪费时间纠结性能吗?
大家在使用 MySQL 的 COUNT 函数时,常见的写法有三种:SELECT COUNT(*)、SELECT COUNT(1) 和 SELECT COUNT(列名) 。那么这三种写法究竟有什么不同呢?在什么场景下应该用什么写法,才能使查询效率最高呢?
一、基础知识
COUNT() 函数用于返回指定列的行数(即记录数)。它有以下几种写法:
- COUNT(*): 统计表中所有行数,包括 NULL 值;
- COUNT(列名):统计指定列的行数,但忽略 NULL 值;
- COUNT(常量) 或 COUNT(1):统计表中所有行的行数,包括 NULL 值。
-- 统计表中所有记录数,包括 NULL 值
SELECT COUNT(*) FROM table_name;
-- 统计指定列的记录数,忽略 NULL 值
SELECT COUNT(column_name) FROM table_name;
-- 统计表中所有行记录数,包括 NULL 值
SELECT COUNT(1) FROM table_name;
二、SELECT COUNT(*) 与 SELECT COUNT(1)
SELECT COUNT(*) 和 SELECT COUNT(1) 是两种等价的写法,它们都用于计算表中所有记录的数量。这两种写法之间的主要区别在于语义上有所不同。
SELECT COUNT(*) 的含义是统计表中所有行的数量,包括 NULL 值。
相比之下,SELECT COUNT(1) 的含义是统计表中所有行的数量,并将结果赋值为 1。
在 MySQL 5.7.18 之前,InnoDB 通过扫描聚集索引来处理 SELECT COUNT(*) 语句。从 MySQL 5.7.18 开始,InnoDB 通过遍历最小的可用辅助索引来处理 SELECT COUNT(*) 语句,除非索引或优化器提示指示优化器使用不同的索引。如果不存在辅助索引,则会扫描聚集索引。如果索引记录不完全在缓冲池中,则处理 SELECT COUNT(*) 语句需要一些时间。
那么这两种写法有没有性能差异呢?其实这个问题在 MySQL 的官网中就已经明确说明了,截图如下:


MySQL官网链接:
https://dev.mysql.com/doc/refman/5.7/en/aggregate-functions.html
截图中的官网原话是:
InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.
For MyISAM tables, COUNT(*) is optimized to return very quickly if the SELECT retrieves from one table, no other columns are retrieved, and there is no WHERE clause.
这段话的意思就是:
InnoDB 引擎以相同的方式处理 SELECT COUNT(*) 和 SELECT COUNT(1) 操作。没有性能差异。
对于 MyISAM 表,如果 SELECT 从一个表中检索,没有检索其他列,并且没有 WHERE 子句,则 COUNT(*) 被优化为非常快速地返回。
所以没必要再去纠结 COUNT(*) 和 COUNT(1) 的性能了。
三、SELECT COUNT(列名)
SELECT COUNT(列名) 的含义是统计指定列的非 NULL 值数量。相比 COUNT(*),它明显多了一个步骤就是判断所查询的字段是否为 NULL,所以它的性能要比 COUNT(*) 慢。
四、究竟该使用哪种写法呢?
看完上面对三种写法的讲述,那究竟该使用哪种写法呢?
对于 SELECT COUNT(*) 和 SELECT COUNT(1) 来说,既然InnoDB引擎两者性能一样,而 MyISAM 中 COUNT(*) 被优化,响应快速更快。更重要的是 COUNT(*) 还是SQL92定义的标准统计行数的语法。所以我更建议使用 COUNT(*)。
对于 SELECT COUNT(列名) 来说,它的非 NULL 特性,我认为其实使用 COUNT(*) 查询附带列名非空的 WHERE 条件更为合适。
SQL92(或称为SQL2)是一种数据库语言标准,全称是 Structured Query Language-Part 2: SQL/Foundation。它由美国国家标准学会(ANSI)和国际标准化组织(ISO)联合制定,发布于1992年,是SQL语言的重要标准之一。SQL92规范包括多个部分,定义了SQL语法、数据类型、数据定义、数据操作、事务控制等方面的标准。它的主要目的是确保不同厂商的关系型数据库管理系统(RDBMS)在语言和数据处理一致性方面能够互相兼容和交互操作,使得不同数据库之间可以更方便地进行数据交换和应用开发。
因此,COUNT(*) 才是最优的选择。
五、《阿里巴巴Java开发手册》中的强制规定
另外我们再来看看《阿里巴巴Java开发手册》中的一段【强制】规定

通过上面的讲述,不知道你是否已经明白了这条【强制】规定的原因呢?既然大厂已经这样要求了,何必再究竟用哪一个呢?
六、概要介绍 MySQL 对 COUNT(*) 的优化有哪些
1、利用表元数据
MySQL 在表执行查询之前会从系统中的缓存中加载表的元数据信息,包括表的行数、列数和列名等。当执行 COUNT(*) 查询时,MySQL 可以直接从表的元数据中读取行数信息,而不用扫描整个表。这种方式可以加快 COUNT(*) 查询的速度。
2、利用 MyISAM 存储引擎
MyISAM 存储引擎是 MySQL 中常用的一种存储引擎,它支持表级别的锁定和高速计数。当执行 COUNT(*) 查询时,如果表使用 MyISAM 存储引擎,MySQL 将使用表级别的计数器来计算表中的行数,从而提高查询性能。
3、利用缓存
MySQL 还可以利用查询结果缓存来提高 COUNT(*) 查询的速度。当执行 COUNT(*) 查询时,MySQL 会首先检查查询结果是否已经缓存,并根据缓存情况来执行查询。如果查询结果已经被缓存,则 MySQL 直接返回缓存结果,否则继续执行查询并将结果缓存在内存中。
4、利用索引
当表中存在索引时,MySQL 可以利用索引进行 COUNT(*) 查询的优化。如果所有列都是索引列或者部分列是索引列,MySQL 可以扫描索引而不是整个表来计算 COUNT(*) 的值,从而提高查询效率。
相关推荐
-
PHP8种变量类型的详细讲解2025-02-22 00:32:24
-
php+apache 和 php+nginx的区别2025-02-22 00:21:27
-
PHP:与workerman结合实现定时任务2025-02-22 00:15:57
-
Nginx的Rewrite规则与实例2025-02-22 00:15:39
-
MySql中身份证字段的简单脱敏介绍2025-02-22 00:15:36