MySQL:COUNT(*) 、 COUNT(1) 和 COUNT(字段) 哪个效率高?

讨论归纳:

先来看看MySQL官方对SELECT COUNT的定义:
传送门:https://dev.mysql.com/doc/refman/5.6/en/aggregate-functions.html#function_count

大概可以分下面这几个步骤讨论。

COUNT(expr)的分析

COUNT(expr)函数返回的值是由SELECT语句检索的行中expr表达式非null的计数值,一个BIGINT的值。 如果没有匹配到数据,COUNT(expr)将返回0,通常有下面这三种用法:

1、COUNT(字段) 会统计该字段在表中出现的次数,忽略字段为null 的情况。即不统计字段为null 的记录。

2、COUNT(*) 则不同,它执行时返回检索到的行数的计数,不管这些行是否包含null值,

3、COUNT(1)跟COUNT(*)类似,不将任何列是否null列入统计标准,仅用1代表代码行,所以在统计结果的时候,不会忽略列值为NULL的行。

所以执行以下数据会出现这样的结果(这边是故意给component字段设置了几个null值):


count(*) 包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL
count(1) 包括了忽略所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULL
count(字段) 只包括字段那一列,在统计结果的时候,会忽略列值为null的计数,即某个字段值为NULL时,不统计。

关于 COUNT(*) 和 COUNT(1)

先看看COUNT(),MyISAM 引擎会把一个表的总行数记录了下来,所以在执行 COUNT() 的时候会直接返回数量,执行效率很高。对于InnoDB这样的事务性存储引擎, 因为增加了版本控制(MVCC)的原因,同时有多个事务访问数据并且有更新操作的时候,每个事务需要维护自己的可见性,那么每个事务查询到的行数也是不同的,所以不能缓存具体的行数,他每次都需要 count 计算一下所有的行数。


关于 COUNT(*) 和 COUNT(1)
关于COUNT(字段)

我们再来看看的COUNT(字段),他的查询就简单粗暴了,就是进行全表扫描,然后判断拿到的字段的值是不是为NULL,不为NULL则累加。

相比COUNT(),COUNT(字段)多了一个步骤就是判断所查询的字段是否为NULL,所以他的性能要比COUNT()和COUNT(1)慢。

总结 :

综上,COUNT(1)和 COUNT(*)表示的是直接查询符合条件的数据库表的行数。而COUNT(字段)表示的是查询符合条件的列的值,并判断不为NULL的行数的累计,效率自然会低一点,

除了查询得到结果集有区别之外,相比COUNT(1) 和 COUNT(字段)来讲,COUNT(*)是SQL92定义的标准统计数的语法,是官方提供的标准方案,基于此,MySQL数据库对他进行过很多优化。


使用建议:

根据总结的内容,从效率层面说,# COUNT (※) ≈ COUNT(1) > COUNT(字段),又因为 COUNT (※) 是SQL92定义的标准统计数的语法,我们建议使用 COUNT(*)。

我们再来看看MySQL数据库做了哪些优化:以MySQL中比较常用的执行引擎InnoDB和MyISAM为例子。

1、MyISAM不支持事务,MyISAM中的锁是表级锁;

因为MyISAM的锁是表级锁,所以同一张表上面的操作是串行执行的,MyISAM把表的总行数单独记录下来,如果只是使用COUNT(*)对表进行查询的时候,可以直接返回这个记录的数值就可以了。

这样表中总行数记录即可提供给COUNT(*)查询使用,又因MyISAM数据库是表级锁,数据库行数不会被并行修改,所以行数是准确无误的。

2、InnoDB支持事务,其中大部分操作都是行级锁。

这样就不能愉快的做这种缓存操作了,因为表的行数可能会被并发修改,缓存记录下来的总行数就不准确了。

在InnoDB中,使用COUNT(*)查询行数的时候,不需要进行扫表,只要获取记录行数而已。所以官方在针对InnoDB的 SELECT COUNT(※) FROM 语句执行过程,会自动选择一个成本较低的索引进行的话,这样就可以大大节省时间。

InnoDB中索引分为聚簇索引(主键索引)和非聚簇索引(非主键索引),聚簇索引的叶子节点中保存的是整行记录,而非聚簇索引的叶子节点中保存的是该行记录的主键的值,非聚簇索引要比聚簇索引小很多,MySQL会优先选择最小的非聚簇索引来扫表,这样可以保证COUNT(*)的最优效率。

当查询语句中包含WHERE以及GROUP BY条件,会有一些其他的因素影响,所以要综合考虑。

原文:https://www.cnblogs.com/wzh2010/p/13795093.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值