聊一聊關於MySQL的count(*)

堅持更新Java技術棧相關總結,Java、MySQL、各種中間件等,關注公衆號【阿丸筆記】獲取第一時間更新。
收集技術相關電子書、面試題,有需要的小夥伴可以關注公衆號【阿丸筆記】,無套路領取。

1. 背景

自從大家對於MySQL數據庫的穩定性有了更高的追求後,經常有小夥伴有這樣的疑問,對於count(*)這樣的操作,有沒有正確的姿勢,或者有沒有可以優化的地方?
但答案比較殘酷,如果已經使用了正確的索引,那麼基本上沒有可以優化的地方。
一旦出現慢查詢了,它就是慢查詢了,要改,只能自己計數或者通過其他搜索平臺來做。
今天,就一起來看看爲什麼會這樣,並對大家日常會遇到的一些的困惑進行解答。

2. count(*)的實現方式

據說,MyISAM 引擎把一個表的總行數存在了磁盤上,因此執行 count(*) 的時候會直接返回這個數,效率很高。
而我們的mysql一般都是用Innodb的引擎,Innodb是怎麼實現count操作的呢?
InnoDB 引擎就比較麻煩了,它執行 count(*) 的時候,需要把數據一行一行地從引擎裏面讀出來,然後累積計數。
所以,當我們的表裏面的記錄越來越多的時候,count(*)就會越來越慢。
當然,我們這裏說的都是不帶where條件的,如果帶上where條件的話,MyISAM也是很慢的。

3.正確的打開方式

嗯,首先還是說,mysql上不太推薦用count(*)來做統計相關業務,尤其是表非常大的情況下。
那如果業務比較小,需要快速上馬,那麼,至少應該保證count(*)帶上了科學的where條件,然後,這個表也已經建立了科學的索引。

  • 如果count(*)帶上的where條件,而且能夠走覆蓋索引,那還是可以偶爾走一走的。
  • 如果count(*)帶上的where條件,能夠走索引,但是需要回表,那麼這種就會比較危險,尤其是隨着表規模的擴大,終究是一顆雷。
  • 如果純粹count(*),或者where條件沒有任何索引,萬萬萬不推薦!

那對於統計類的業務,推薦的幾種做法:

  • 帶自增id的,可以用最大id來近似獲取
  • 自己計數
  • 其他數據分析平臺進行聚合

4. 能否用表統計信息代替count(*)

有同學在日常使用過程中,問能否使用 系統表的統計信息 來代替count。
答案是不行。
這裏的tableRows只是一個參考值。
這裏的表統計信息,實際上是使用show table status獲取的。這個值是如何得到的呢?我們需要了解下mysql的採樣統計方法。爲什麼要採樣統計呢?
因爲把整張表取出來一行行統計,雖然可以得到精確的結果,但是代價太高了,所以只能選擇“採樣統計”(所以其實mysql自己也沒有count(*)的好方法)。
採樣統計的時候,InnoDB 默認會選擇 N 個數據頁,統計這些頁面上的不同值,得到一個平均值,然後乘以這個索引的頁面數,就得到了這個索引的基數。而數據表是會持續更新的,索引統計信息也不會固定不變。
所以,當變更的數據行數超過 1/M 的時候,會自動觸發重新做一次索引統計。
因此,這個採樣估算得來的值,是很不準的。有多不準呢,官方文檔說誤差可能達到 40% 到 50%。

4.關於那些奇奇怪怪的count(?)

在看一些老代碼查詢的時候,我們經常會看到count(1),count(id),count(字段)等方式,那它們糾結孰優孰劣,到底有沒有性能上的差異呢?
這裏,我們先要弄清楚 count() 的語義。
count() 是一個聚合函數,對於返回的結果集,一行行地判斷,如果 count 函數的參數不是 NULL,累計值就加 1,否則不加。最後返回累計值。

  • count(主鍵id)InnoDB 引擎會遍歷整張表,把每一行的 id 值都取出來,返回給 server 層。server 層拿到 id 後,判斷是不可能爲空的,就按行累加
  • count(1)InnoDB 引擎遍歷整張表,但不取值。server 層對於返回的每一行,放一個數字“1”進去,判斷是不可能爲空的,按行累加。
  • count(字段)如果這個“字段”是定義爲 not null 的話,一行行地從記錄裏面讀出這個字段,判斷不能爲 null,按行累加;如果這個“字段”定義允許爲 null,那麼執行的時候,判斷到有可能是 null,還要把值取出來再判斷一下,不是 null 才累加。
  • count(*)並不會把全部字段取出來,而是專門做了優化,不取值。count(*) 肯定不是 null,按行累加。

所以結論是:按照效率排序的話,count(字段)<count(主鍵 id)<count(1)≈count(*),所以我建議,儘量使用 count(*)。

掃碼關注我的公衆號“阿丸筆記”,第一時間獲取最新更新。
無套路獲取Java技術棧電子書、各個大廠面試題。
阿丸筆記

發佈了26 篇原創文章 · 獲贊 1 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章