MySQL必须用 COUNT(列),不准用COUNT(*)?
COUNT 是数据库人用凌波微步也躲不开的一道坎。
关于COUNT的使用,有很多不知道为什么的结论,比如:
- SQL必须用 COUNT(列),不准用COUNT(*),COUNT(*)比COUNT(列)慢?
- 在使用COUNT的时候要用COUNT(1)而不要用COUNT(*),因为使用COUNT(*)的时候会对所有的列进行扫描,相比而言COUNT(1)不用扫描所有列,所以COUNT(1)要快一些?
这些让人深信不疑,奉为圭臬的结论,到底正不正确?对我们的工作来说,究竟应该在哪种场景下使用哪个?
实验结论是:
- COUNT(1)和COUNT(*) 并没有区别
- COUNT(*) 和 COUNT(列) 在没有索引的情况下一样快
- 在有索引的情况下,如果该列允许为空,是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)查询也都会使用主键索引。即两者并没有区别。
最后,给大家分享畅销书作家成甲的一句话,“那些能够改变你行动的信息,我们称之为知识”,希望本文带给大家的是知识而不只是信息~
___________________________________
原文:https://www.toutiao.com/a6657747116590367245/?iid=60089825868&app=news_article_lite&is_hit_share_recommend=0&tt_from=copy_link&utm_source=copy_link&utm_medium=toutiao_ios&utm_campaign=client_share