搞定面試官 - MySQL 中,對于 COUNT() 如何正確使用?
? ?

大家好,我是程序員啊粥。
相信在大家的工作中,有很多的功能都需要用到 count(*) 來統(tǒng)計表中的數據行數。同時,對于一些大數據的表,用 count 都是瑟瑟發(fā)抖,往往會結合緩存等進行處理。
那么,我們今天就來分析一下,在 InnoDB 中,關于 count 的一些處理措施和優(yōu)化。 ?
常見的 count 三種使用方式
-
count(*)
-
count(主鍵 Id)/count(某個字段)
-
count(1)
首先 count(*)、count(主鍵 Id)/count(某個字段) 和 count(1) 都表示返回滿足條件的結果集的總行數。
各自用法的差異
他們的差異在于:count(字段)表示返回滿足條件的數據行里面,參數“字段”不為 NULL 的總條數,而 count(1) 會統(tǒng)計表中的所有的記錄數,包含字段為 NULL 的記錄,但它是用 1 代替了所有列,不在關注表中具體列的情況,count(*) 包括了所有的列,相當于行數,在統(tǒng)計結果的時候,它同樣不會忽略為 NULL 的值。
接下來,我們就一個個地來看看。
COUNT(主鍵ID)
對于 count(主鍵 id) 來說,InnoDB 引擎會遍歷整張表,把每一行的 id 值都取出來,返回給 server 層。server 層拿到 id 后,判斷是不可能為空的,就按行累加。
COUNT(1)
對于 count(1) 來說,InnoDB 引擎遍歷整張表,但不取值。server 層對于返回的每一行,放一個數字“1”進去,判斷是不可能為空的,按行累加。
單看這兩個用法的差別的話,相信你能對比出來,count(1) 執(zhí)行得要比 count(主鍵 id) 快。因為從引擎返回 id 會涉及到解析數據行,以及拷貝字段值的操作,少一步操作就能少一些時間。
同時對于 count(字段) 來說:如果這個“字段”是定義為 Not Null 的話,一行行地從記錄里面讀出這個字段,判斷發(fā)現這個字段不能為 Null,那么直接按行累加;但是如果這個“字段”定義允許為 Null 的話,那么執(zhí)行的時候,還要把具體的字段值取出來再判斷一下,不是 Null 才能進行累加。
COUNT(*)的優(yōu)化
count(*) 是例外,MySQL 專門對其做出了優(yōu)化,MySQL 每發(fā)布一個新版本,都會放出相應的 Release Notes,我們注意到 5.7.2 版本的發(fā)布說明中提到:
InnoDB:
SELECT COUNT(*) FROM tstatements 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 improvesSELECT COUNT(*) FROM tperformance. 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() 的用法,你用對了嘛?
評論區(qū)留言我們一起討論哇!
我是程序員阿粥,關注我,我們一起在技術世界中向上生長。
