打破讹传:MySQL必须用 COUNT(列),不准用COUNT(*)?

COUNT 是数据库人用凌波微步也躲不开的一道坎。

关于COUNT的使用,有很多不知道为什么的结论,比如:

  • SQL必须用 COUNT(列),不准用COUNT(*),COUNT(*)比COUNT(列)慢?
  • 在使用COUNT的时候要用COUNT(1)而不要用COUNT(*),因为使用COUNT(*)的时候会对所有的列进行扫描,相比而言COUNT(1)不用扫描所有列,所以COUNT(1)要快一些?

这些让人深信不疑,奉为圭臬的结论,到底正不正确?对我们的工作来说,究竟应该在哪种场景下使用哪个?

打破讹传:MySQL必须用 COUNT(列),不准用COUNT(*)?

实验结论是:

  1. COUNT(1)和COUNT(*) 并没有区别
  2. COUNT(*) 和 COUNT(列) 在没有索引的情况下一样快
  3. 在有索引的情况下,如果该列允许为空,是COUNT(列)快,如果不允许为空,是一样快的。

下面就用5分钟来具体讲讲原因。

一、COUNT是什么?

COUNT()函数返回表中的行数。COUNT()函数允许您对表中符合特定条件的所有行进行计数。

COUNT函数有几种形式:

COUNT(*)、COUNT(column)、COUNT(1)、COUNT(DISTINCT column)和COUNT(expression)。

语法:

1.COUNT(*) 函数返回表中的记录数:

SELECT COUNT(*) FROM table_name

2.COUNT(column_name) 函数返回指定列的值的数目(NULL 不计入):

SELECT COUNT(column_name) FROM table_name

3. COUNT(DISTINCT column_name) 函数返回指定列的不同值的数目:

SELECT COUNT(DISTINCT column_name) FROM table_name

PS: 这里的COUNT(1)中的“1”并不表示表中的第一列,它其实是一个表达式,可以换成任意数字或字符或表达式。

二、COUNT(*)与COUNT(列)的区别

要通透的了解一个知识点,首先需要了解它的本质。

  • COUNT(*)是对全表扫描的统计,不会忽略NULL值,数据库在处理COUNT(*)的时候只需要找到属于表的数据块块头,然后计算一下行数就行了,而不用去读取里面数据列的数据。
  • COUNT(列)是针对于某一列的,如果此列值为空的话,COUNT(列)是不会统计这一行的,所以为了去除列中包含的NULL行,数据库必须读取该列的每一行的值,然后确认下是否为NULL,然后在进行计数。

所以两者根本没有可比性,性能比较首先要考虑写法等价,这两个语句根本就不等价。也就失去了去比较的意义。

两者无关的话,什么场景下用哪个呢?

  • 在统计表全部行数的时候,COUNT(*)是最佳选择;
  • COUNT(列)对应的列字段如果建了索引,且索引列允许空值,则COUNT(列)会走索引,此时选择COUNT(列)。

PS: COUNT(列)如果列字段越往后,则访问的开销越大,执行速度越慢,所以常用的列要放在靠前的位置,但是COUNT(*)并不受此限制。

三、COUNT(*)与COUNT(1)的区别

上文提到的COUNT(1)比COUNT(*)快,给出的理由是COUNT(*)会带来全表扫描。而实际上两者并没有区别。

在MySQL5.7.23.0以后的版本,会默认对主键添加索引,所以结论是:

若表中有索引,COUNT(*)与COUNT(1)均会使用索引。由于MySQL默认对主键添加索引,所以对存在主键的表进行COUNT(*)、COUNT(1)查询也都会使用主键索引。即两者并没有区别。

最后,给大家分享畅销书作家成甲的一句话,“那些能够改变你行动的信息,我们称之为知识”,希望本文带给大家的是知识而不只是信息~

若有不完善的地方,欢迎大家指正~

打破讹传:MySQL必须用 COUNT(列),不准用COUNT(*)?


分享到:


相關文章: