写点什么

MySQL COUNT(列名) 、COUNT(常量) 和 COUNT(*) 之间的区别

用户头像
桃子
关注
发布于: 2021 年 02 月 26 日
MySQL COUNT(列名) 、COUNT(常量) 和 COUNT(*) 之间的区别

COUNT(expr) 官方解释:

  • 返回 SELECT 语句检索的行中 expr 的值不为 NULL 的数量。结果是一个 BIGINT 的值。

  • 查询结果中没有任何记录,则返回 0。

  • COUNT(*) 的统计结果中,会包含值为 NULL 的行数。


COUNT(列名) 、COUNT(常量) 和 COUNT(*) 之间的区别


  • 常量是一个固定值,肯定不为 NULL;

  • 可以理解为查询整行,肯定不为 NULL;

  • 列名的查询结果有可能是 NULL;


所以 COUNT(*) 和 COUNT(常量) 表示的是直接符合条件的数据库表的行数。

而 COUNT(列名)表示的是查询符合条件的列的值不为 NULL 的行数。


COUNT(*) 和 COUNT(常量)的区别:COUNT(*) 是 SQL92 定义的标准统计行数的语法,因为他是标准语法,所以 MYSQL 数据库对他进行过很多优化。


MYSQL 针对 COUNT(*)的优化内容:

MyISAM

  • 当没有 where 条件时,MyISAM 做了一个简单的优化那就是它可以把表的总行数单独记录下来,如果从一张表中使用 COUNT(*) 进行查询的时候,可以直接返回这个记录下来的数值就可以了。

  • MyISAM 的锁是表级锁,所以同一张表上面的更新操作需要串行进行,可以保证查询得到的数据的准确性。

InnoDB

  • 对于 InnoDB 来说,就不能做这种缓存操作了,因为 InnoDB 支持事务,其中大部分操作都是行级锁,所以可能表的行数可能会被并发修改,那么缓存记录下来的总行数就不准确了。

  • 从 MySQL 8.0.13 开始,查询语句中不包含 WHERE 或 GROUP BY,针对 InnoDB 的 SELECT COUNT(*) FROM tbl_name 语句,在扫表的过程中做了一些优化。

  • COUNT(*) 的目的只是为了统计总行数,所以,他根本不关心自己查到的具体值,所以,他如果能够在扫表的过程中,选择一个成本较低的索引进行的话,那就可以大大节省时间。

  • InnoDB 中索引分为聚簇索引(主键索引)和非聚簇索引非主键索引),聚簇索引的叶子节点中保存的是整行记录,而非聚簇索引的叶子节点中保存的是该行记录的主键的值。所以,相比之,非聚簇索引要比聚簇索引小很多,所以 MySQL 会优先选择最小的非聚簇索引来扫表。

  • 当我们建表的时候,除了主键索引以外,创建一个非主键索引还是有必要的。


终于明白了 MySQL 中 COUNT(常量) 和 COUNT(*) 的区别,此刻我感觉我又行了,但是...


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

画重点:same way , no performance difference。所以,对于 COUNT(1)和 COUNT(*),MySQL 的优化是完全一样的,根本不存在谁比谁快!

COUNT(列名)

最后,就是我们一直还没提到的 COUNT( 字段 ),他的查询就比较简单粗暴了,就是进行全表扫描,然后判断指定字段的值是不是为 NULL,不为 NULL 则累加。相比 COUNT(),COUNT( 字段 ) 多了一个步骤就是判断所查询的字段是否为 NULL,所以他的性能要比 COUNT() 慢。


此文非原创,摘抄自 阿里巴巴 《Java 开发手册泰山版》


发布于: 2021 年 02 月 26 日阅读数: 13
用户头像

桃子

关注

还未添加个人签名 2018.04.24 加入

还未添加个人简介

评论

发布
暂无评论
MySQL COUNT(列名) 、COUNT(常量) 和 COUNT(*) 之间的区别