這裏討論的count查詢優化是針對INNODB存儲引擎的!java
首先拋出一個問題sql
count(*)、count(主鍵)、count(1)、count(字段)它們四者之間的效率如何排序?函數
在咱們以往的工做經驗中,老是聽到說不要使用count(*),由於 * 號表明了全部列,計算會更慢,而後就推薦了使用count(主鍵)。但事實真的是這樣嗎?性能
筆者在最近的學習中也才認識到這個錯誤。學習
這四者正確的排序應該是這樣的:測試
count(1) > count(*) > count(主鍵) > count(字段)
筆者特地在一張只有主鍵索引的1千萬條數據的表中作了測試,如下是測試的結果:優化
這張圖的數據不是偶然的,筆者針對每種查詢執行了屢次,結果不會有太大的變化,驗證了以上排序的正確性。code
count()的做用blog
count()是一個特殊的函數,有兩種很是不一樣的做用:它能夠統計某個列值的數量,也能夠統計行數。在統計列值時要求列值排序
是非空的(不統計NULL)。若是在count()的括號中指定了列或者列的表達式,則統計的就是這個表達式有值的結果數,而不是NULL。
count()的另外一個做用是統計結果集的行數。當MYSQL確認括號內的表達式值不可能爲空時,實際上就是在統計行數。最簡單的就
是當咱們使用count(*)的時候,這種狀況下通配符 * 並不會像咱們猜測的那樣擴展成全部的列,實際上,它會忽略全部的列而直接統計
全部的行數。
最多見的一個錯誤就是,在括號內指定了一個列卻但願統計結果集的行數。若是但願知道的是結果集的行數,最好使用COUNT(*),
這樣寫意義清晰,性能也會很好。
count()的另外一個優化
業務代碼中,有這樣一個需求,須要根據一個或多個條件,查詢是否存在記錄,不關心有多少條記錄。廣泛的SQL及代碼寫法以下:
SELECT count(*) FROM T WHERE a = 1 AND b = 2
java寫法以下
Integer exist = xxDao.existXxxxByXxx(params); if ( exist != NULL ) { //當存在時,執行這裏的代碼 } else { //當不存在時,執行這裏的代碼 }
對於此處的select count(*),並不需求將符合條件的條數都統計出來,能夠優化成以下的SQL:
SELECT count(*) FROM T WHERE a = 1 AND b = 2 LIMIT 1
這裏相比上面的SQL多了LIMIT關鍵字,在MYSQL中,執行器執行到LIMIT關鍵字,只要知足LIMIT的條數,存儲引擎就不會再對數據文件
進行檢索,直接返回,因此這裏只須要檢索到1條以後就返回結果,效率可想而知快了很多!