MySQL優化COUNT()查詢

AmosH發表於2019-01-14

COUNT()聚合函式,以及如何優化使用了該函式的查詢,很可能是最容易被人們誤解的知識點之一

COUNT()的作用

COUNT()是一個特殊的函式,有兩種非常不同的作用:

  1. 統計某個列值的數量
  2. 統計行數

統計列值

在統計列值時,要求列值是非空的,即不統計NULL。如果在COUNT()的括號中指定了列或者列的表示式,則統計的就是這個表示式有值的結果數。

統計結果集的行數

當MySQL確認括號內的表示式的值不可能為空時,實際上就是在統計行數,最簡單的就是當我們使用COUNT(*)的時候,這種情況下萬用字元 * 並不會像我們猜想的那樣擴充成所有的列,實際上,它會忽略所有的列而直接統計所有的行數。

因此會有一個常見的錯誤就是,在括號內指定了一個列卻希望統計結果集的行數。如果希望知道的是結果集的行數,那麼最好使用COUNT(*)。這樣寫意義清晰,效能也會更好。

關於MyISAM的神話

一個很容易產生的誤解就是:MyISAM的COUONT()函式總是非常快的,但其實這是有一個前提條件的,即只有沒有任何WHERE條件的COUNT(*)才非常快,因為此時無需實際地計算表的行數。MySQL可以利用儲存引擎的特性直接獲得這個值。

當統計帶有WHERE子句的結果集行數時,可以是統計某個列值的數量時,MyISAM的COUNT()和其他儲存引擎沒有任何不同,也就不再是神話般的速度了。

簡單的優化

有時候我們可以使用MyISAM在 COUNT(*) 全表非常快的這個特性,來加速一些特定條件的 COUNT() 查詢。比如:

SELECT COUNT(*) FROM world.City WHERE ID > 5;

該查詢查詢所有ID大於5的城市,這需要掃描4097行資料。但是如果我們把條件反轉一下,查詢ID小於等於5的城市的數量,然後用總城市的數量一減就可以得到同樣的結果,但是卻可以把掃描的行數控制在5行以內:

SELECT (SELECT COUNT(*) FROM world.City) - COUNT(*)
FROM world.City WHERE ID <= 5;

使用近似值

有些時候並不需要完全精確的COUNT的值,此時可以用近似值來代替。EXPLAIN出來的優化器估算的行數就是一個不錯的近似值,執行EXPLAIN並不需要真正去執行查詢,所以成本很低。

相關文章