MySQL中count(field),count(*),count(常量)的區別

一 概要

最近在研究mybatis的時候發現**Mapper.xml在編寫SQL的時候發現聚合函數(count())使用起來挺方便,count() 是一個聚合函數,對於返回的結果集,一行行地判斷,如果 count 函數的參數不是 NULL,累計值就加 1,否則不加,最後返回累計值。

<select id="checkEmail" parameterType="string" resultType="int">
    select count(*) from mark_user
    where email = #{email}
</select>

此處使用的是count(*),而且在阿里巴巴開發手冊中強制要求使用count(*),原文如下:

count(*),count(常量),count(field)的概述:

count(*) 和 count(常量)直接查詢符合條件的數據庫表的行數,而count(field)則會查詢符合NOT NULL的數據庫行數。此外count(*)時SQL92定義的標準統計行數的語法,而且MySQL數據庫對其進行過很多優化。

SQL92,是數據庫的一個ANSI/ISO標準。它定義了一種語言(SQL)以及數據庫的行爲(事務、隔離級別等)。

二 count(*),count(常量),count(field)的區別

執行條件 執行方法 MySQL中執行的結果 不同count方法的總結
存在where語句 count(*) count(常量)如(count(1)) 和 count(*)表示的是直接查詢符合條件的數據庫的行數,而 count(field)(field的可以理解爲表的列名)表示的是查詢符合條件的列的值不爲NULL的行數。
count(1)
count(field)
當數據庫中某指定字段NULL時,如上圖中phone字段的第5條數據爲NULL count(*)

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

對於 count(field) 來說:

1.如果這個字段定義爲NOT NULL的時候,一行一行地從記錄裏面讀取這個字段,判斷不能爲NOT NULL,按行累加;

2.如果這個字段允許爲NULL的時候,在執行存在NULL的情況,這時候判斷不是NULL的時候纔會累加。

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

 

 

count(field)
count(1)

MySQL官方文檔:InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.

對於count(1)count(*),MySQL的優化是完全一樣的,根本不存在誰更快!但依舊建議使用count(*),因爲這是SQL92定義的標準統計行數的語法。

而count(field)進行全表掃描,判斷指定字段的值是否爲NULL,不爲NULL則累加。性能比count(1)count(*)慢。所以,按照函數的執行效率排序爲可以認爲結果爲: count(field) < count(主鍵 id) < count(1) ≈ count(*)。

三 count(*)的優化

MySQL中兩種主要執行引擎:

1. InnoDB引擎:InnoDB支持事務,大部分操作行級鎖,行可能被並行修改,那麼緩存記錄不準確。而且InnoDB針對count(*)通過低成本的索引進行掃表,而不關注表的具體內容。InnoDB中索引分爲聚簇索引(主鍵索引)和非聚簇索引(非主鍵索引),聚簇索引的葉子節點中保存的時整行數據,而非聚簇索引的葉子節點保存到時該行記錄的主鍵值。同時MySQL會優先選擇最小的非聚簇索引來掃表。這些優化的前提是查詢語句中不包含where條件和group by 條件。

2. MyISAM引擎:MyISAM做了一個簡單的優化,把表的總行數單獨記錄下來,如執行count(*)時可以直接返回,前提時不能有where條件的。MyISAM時表級鎖,不會有併發的行操作,所以查到的結果時準確的。

MyISAM不支持事務,MyISAM中的鎖是表級鎖,而InnoDB支持事務,並且支持行級鎖。

四 總結

        聚合函數count()主要是用於統計表行數,主要用法有count(*),count(1),count(主鍵id)和count(field);

其中count(*)是SQL92定義的標準統計行數的語法,MySQL對其進行了很多優化,MyISAM中會直接把表的總行數單獨記錄下提供給count(*),而InnoDB則會在掃表的時候選擇最小的索引(非聚簇索引,其葉子節點保存的是主鍵值)來降低成本,前提是,查詢語句中不能夠存在where和group條件。

在InnoDB中,count(*) 和 count(1)實現上沒有區別,效率等同,當時count(field)則需要對字段進行非UNLL判斷,所以效率會有所下降。

綜上所述可得爲什麼阿里巴巴開發手冊上強制規定不能夠用count(列名)和count(常量)來代替count(*);

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