Beaver's Blog

Freedom Openness Inclusion

0%

MySQL中COUNT函数的解释

COUNT的作用

COUNT函数在数据库可以用来统计行数,可以是表的总行数,也可以用来统计某一列的行数,或者符合条件的结果的行数。现在来看下MySQL官方文档对函数的功能描述:

Returns a count of the number of NON-NULL values of expr in the rows retrieved by a SELECT statement. The result is a BIGINT value. If there are no matching rows, COUNT() returns 0.
COUNT(DISTINCT exp): Returns a count of the number of rows with different non-NULL expr values.

注意:使用COUNT([DISTINCT] expr)统计expr时,统计的是non-null的行数。

以下是COUNT函数的具体使用:

1
2
3
4
5
6
7
8
9
-- 统计表的总行数
SELECT COUNT(*) FROM T1
-- 统计列的数量
SELECT COUNT(COLUMN1) FROM T1
-- 带有过滤条件的统计
SELECT COUNT(*) FROM T1,T2 WHERE T1.ID=T2.ID AND T1.ID>100;
SELECT COUNT(T1.ID) FROM T1,T2 WHERE T1.ID=T2.ID AND T1.ID<1000;
-- DISTINCT去重
SELECT COUNT(DISTINCT C1) FROM T1;

COUNT(1) VS COUNT(*)

COUNT(1)COUNT(*)在功能上一样,都是用来统计行数。但这里要讨论的区别,主要是指数据库性能上的差异。有些人可能会觉得,COUNT(1)会比COUNT(*)性能更好一些。但是,根据MySQL官方文档的解释,在Innodb存储引擎中,其实二者并没有性能上的差异[1]。以下是MySQL官方解释:

InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.

COUNT函数与存储引擎

对于Innodb存储引擎,执行COUNT(*)统计行数,需要对表一行一行的计数统计。但对于采用了MyISAM存储引擎的表,COUNT(*)的速度非常快,这是因为MySQL可以利用MyISAM的存储引擎特性(MyISAM 引擎把一个表的总行数存在了磁盘上)直接获得这个值,但这也只适用于没有WHERE条件的COUNT(*),即SELECT COUNT(*) FROM tMyISAM在处理使用了过滤条件的统计或统计部分列,其实速度与别的存储引擎并没有什么不同[1]

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.

  • 如何从事务的角度分析 InnoDBCOUNT(?)

    由于 InnoDB 引擎支持事务的特性,数据表中的一行记录,可能有多个版本 (row),每个版本有自己的 row trx_id。所以,对于InnoDB引擎来说,不同事务中count(?)的结果可能是不一致的。

总结

使用了MyISAM 引擎的表, COUNT(*) 速度很快,但是MyISAM引擎不支持事务,而且含有 where 条件 COUNT与别的引擎没什么不同。
show table status 命令虽然返回很快,但是结果不够准确[2]
对使用了InnoDB 引擎的表直接 COUNT(*) 的结果很准确,但会遍历全表,这可能会导致性能问题。
效率对比:count(*)~count(1)>count(column_x)

参考文档

[1] MySQL 8.0 Reference Manual: Aggregate Function Descriptions - count

[2] MySQL 8.0 Reference Manual: SHOW TABLE STATUS Statement