count(*)、count(主鍵id)、count(字段)、count(1)實現原理和性能比較

       在工作中我們或多或少都會遇到統計數據的需求,那麼問題來了,count(*)、count(主鍵id)、count(字段)、count(1) 這些操作,我們到底用哪個比較合適呢。

count() 的語義

       count() 是一個聚合函數,對於返回的結果集,一行行地判斷,如果 count 函數的參數不是 NULL,累計值就加 1,否則不加。最後返回累計值。

MySQL 不同引擎,count()的實現方式

  • MyISAM 引擎把一個表的總行數存在了磁盤上,因此執行 count(*) 的時候會直接返回這個數,效率很高;
  • InnoDB 引擎,它執行 count() 的時候,需要把數據一行一行地從引擎裏面讀出來,然後累積計數。

我們以 InnoDB 引擎 進行分析:

count(*)

       InnoDB 是索引組織表,主鍵索引樹的葉子節點是數據,而普通索引樹的葉子節點是主鍵值。所以,普通索引樹比主鍵索引樹小很多。對於 count(*) 這樣的操作,遍歷哪個索引樹得到的結果邏輯上都是一樣的。因此,MySQL 優化器會找到最小的那棵樹來遍歷。在保證邏輯正確的前提下,儘量減少掃描的數據量,是數據庫系統設計的通用法則之一

count(主鍵id)

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

count(1)

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

count(字段)

  • 如果這個“字段”是定義爲 not null 的話,一行行地從記錄裏面讀出這個字段,判斷不能爲 null,按行累加;
  • 如果這個“字段”定義允許爲 null,那麼執行的時候,判斷到有可能是 null,還要把值取出來再判斷一下,不是 null 才累加。

count(1) 執行得要比 count(主鍵 id) 快。因爲從引擎返回 id 會涉及到解析數據行,以及拷貝字段值的操作。

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

參考文檔

       https://time.geekbang.org/column/article/72775

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