打破訛傳: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(*)?


分享到:


相關文章: