MySQL中的count(主鍵 id)、count(字段) 和 count(1)


需要注意的是,下面的討論還是基於 InnoDB 引擎的。

 

這里,首先你要弄清楚 count() 的語義。count() 是一個聚合函數,對於返回的結果集,一行行地判斷,如果 count 函數的參數不是 NULL,累計值就加 1,否則不加。最后返回累計值。

 

所以,count(*)、count(主鍵 id) 和 count(1) 都表示返回滿足條件的結果集的總行數;而 count(字段),則表示返回滿足條件的數據行里面,參數“字段”不為 NULL 的總個數。

 

至於分析性能差別的時候,你可以記住這么幾個原則:

  • server 層要什么就給什么;
  • InnoDB 只給必要的值;
  • 現在的優化器只優化了 count(*) 的語義為“取行數”,其他“顯而易見”的優化並沒有做。

 

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

 

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

 

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

 

對於 count(字段) 來說:

  1. 如果這個“字段”是定義為 not null 的話,一行行地從記錄里面讀出這個字段,判斷不能為 null,按行累加;
  2. 如果這個“字段”定義允許為 null,那么執行的時候,判斷到有可能是 null,還要把值取出來再判斷一下,不是 null 才累加。
  • 也就是前面的第一條原則,server 層要什么字段,InnoDB 就返回什么字段。

 

但是 count(*) 是例外,並不會把全部字段取出來,而是專門做了優化,不取值。count(*) 肯定不是 null,按行累加。

 

看到這里,你一定會說,優化器就不能自己判斷一下嗎,主鍵 id 肯定非空啊,為什么不能按照 count(*) 來處理,多么簡單的優化啊。

 

當然,MySQL 專門針對這個語句進行優化,也不是不可以。但是這種需要專門優化的情況太多了,而且 MySQL 已經優化過 count(*) 了,你直接使用這種用法就可以了。

 

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

 

 

轉載請注明出處!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM