搞定面試官 - 可以介紹一下在 MySQL 中你平時是怎麼使用 COUNT() 的嘛?

大家好,我是程序員啊粥。

相信在大家的工作中,有很多的功能都需要用到 count(*) 來統計表中的數據行數。同時,對於一些大數據的表,用 count 都是瑟瑟發抖,往往會結合緩存等進行處理。

那麼,我們今天就來分析一下,在 InnoDB 中,關於 count 的一些處理措施和優化。

常見的 count 使用方式有三種

  • count(*)
  • count(主鍵 Id)/count(某個字段)
  • count(1)

首先 count(*)、count(主鍵 Id)/count(某個字段) 和 count(1) 都表示返回滿足條件的結果集的總行數。

他們的差異在於:count(字段)表示返回滿足條件的數據行裏面,參數“字段”不爲 NULL 的總條數,而 count(1) 會統計表中的所有的記錄數,包含字段爲 NULL 的記錄,但它是用 1 代替了所有列,不在關注表中具體列的情況,count(*) 包括了所有的列,相當於行數,在統計結果的時候,它同樣不會忽略爲 NULL 的值。

接下來,我們就一個個地來看看。

對於 count(主鍵 id) 來說,InnoDB 引擎會遍歷整張表,把每一行的 id 值都取出來,返回給 server 層。server 層拿到 id 後,判斷是不可能爲空的,就按行累加。

對於 count(1) 來說,InnoDB 引擎遍歷整張表,但不取值。server 層對於返回的每一行,放一個數字“1”進去,判斷是不可能爲空的,按行累加。

單看這兩個用法的差別的話,相信你能對比出來,count(1) 執行得要比 count(主鍵 id) 快。因爲從引擎返回 id 會涉及到解析數據行,以及拷貝字段值的操作,少一步操作就能少一些時間。

同時對於 count(字段) 來說:如果這個“字段”是定義爲 Not Null 的話,一行行地從記錄裏面讀出這個字段,判斷髮現這個字段不能爲 Null,那麼直接按行累加;但是如果這個“字段”定義允許爲 Null 的話,那麼執行的時候,還要把具體的字段值取出來再判斷一下,不是 Null 才能進行累加。

但是 count(*) 是例外,MySQL 專門對其做出了優化,MySQL 每發佈一個新版本,都會放出相應的 Release Notes,我們注意到 5.7.2 版本的發佈說明中提到:

InnoDB: SELECT COUNT() FROM t statements now invoke a single handler call to the storage engine to scan the clustered index and return the row count to the Optimizer. Previously, a row count was typically performed by traversing a smaller secondary index and invoking a handler call for each record. A single handler call to the storage engine to count rows in the clustered index generally improves SELECT COUNT() FROM t performance. However, in the case of a large clustered index and a significantly smaller secondary index, performance degradation is possible compared to performance using the previous, non-optimized implementation. For more information, see Limits on InnoDB Tables.

簡單地說就是:COUNT(*)會選擇聚集索引,進行一次內部 handler 函數調用,即可快速獲得該錶行數

所以,它也不存在需要取值判斷是否爲 Null 的計算操作,可以說效率有很大的提高。

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

而不是受我們慣性思維的影響,覺得 count(*) 可能和 select() 一樣,效率會很低,反之,這是效率最高的。

當然,你如果實際中遇到了大數據量的表,可能把具體的行數緩存下來,或者專門建立一張表來存儲這個 count() 值,而不是每次都去表裏掃描一次。

好了,今天的內容到此就結束了,關於 count() 的用法,你用對了嘛?

評論區留言我們一起討論哇!

我是程序員啊粥,關注我,我們一起在技術海洋中向上生長。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章