`SELECT COUNT( ) FROM table_name`是個再常見不過的統計需求了。 本文帶你瞭解下 的`COUNT`函數。 一、 函數 關於 函數,在 官網中有 "詳細介紹" : 翻譯一下: 1. ,返回 語句檢索的行中 的值不為 的數量,結果是一個 值。 1. 如果查詢結果沒有命中任何 ...
SELECT COUNT(*) FROM table_name
是個再常見不過的統計需求了。
本文帶你瞭解下Mysql
的COUNT
函數。
一、COUNT
函數
關於COUNT
函數,在MySQL
官網中有詳細介紹:
翻譯一下:
COUNT(expr)
,返回SELECT
語句檢索的行中expr
的值不為NULL
的數量,結果是一個BIGINT
值。- 如果查詢結果沒有命中任何記錄,則返回
0
COUNT(*)
的統計結果中,會包含值為NULL
的行數。
在《阿裡巴巴Java開發手冊》也有如下要求:
二、COUNT(列名)
、COUNT(常量)
和COUNT(*)
前面我們提到過
COUNT(expr)
用於做行數統計,那麼COUNT(列名)
、COUNT(常量)
和COUNT(*)
這三種語法中,expr
分別是列名、 常量 和*
。
2.1 COUNT(*)
和COUNT(常量)
在列名、常量和*
這三個條件中,常量是一個固定值,肯定不為NULL
。*
可以理解為查詢整行,所以肯定也不為NULL
,那麼就只有列名的查詢結果可能是NULL
。
所以, COUNT(常量)
和 COUNT(*)
表示的是直接查詢符合條件的資料庫表的行數。而COUNT(列名)
表示的是查詢符合條件的列的值不為NULL
的行數。
2.2 COUNT(*)
和COUNT(1)
區別
COUNT(1)
就是COUNT(常量)
,對於這二者到底有沒有區別:
- 有的說
COUNT(*)
執行時會轉換成COUNT(1)
,所以COUNT(1)
少了轉換步驟,所以更快。 - 還有的說,因為
MySQL
針對COUNT(*)
做了特殊優化,所以COUNT(*)
更快。
到底哪種說法是對的?看下MySQL
官方文檔:
InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.
通過文檔,對於COUNT(1)
和COUNT(*)
,MySQL
的優化是完全一樣的,根本不存在誰比誰快!
2.3 COUNT(列名)
相較於前兩者,COUNT(列名)
的查詢就比較簡單粗暴了,就是進行全表掃描,然後判斷指定欄位的值是不是為NULL
,不為NULL
則累加。
相比
COUNT(*)
,COUNT(列名)
多了一個步驟就是判斷所查詢的欄位是否為NULL
,所以他的性能要比COUNT(*)
慢。
here和group的條件查詢。
2.4 SQL92
除了查詢得到結果集有區別之外,COUNT(*)
相比COUNT(常量)
和 COUNT(列名)
來講,COUNT(*)
是SQL92
定義的標準統計行數的語法,因為他是標準語法,所以MySQL
資料庫對他進行過很多優化。
SQL92
,是資料庫的一個ANSI/ISO
標準。它定義了一種語言(SQL
)以及資料庫的行為(事務、隔離級別等)。
2.5 COUNT(*)
優化
因為COUNT(*)
是SQL92
定義的標準統計行數的語法,所以MySQ
L對其進行了很多優化:
MyISAM
中會直接把表的總行數單獨記錄下來供COUNT(*)
查詢InnoDB
會在掃表的時候選擇最小的索引來降低成本。
這些優化的前提都是沒有進行
where
和group
的條件查詢,更多請參考MySQL 全表 COUNT(*) 簡述
三、總結
COUNT
函數用於統計表行數,按照效率比較的話:
count(*)=count(常量)>count(列名)
3.1 小建議
既然 count(*)
在查詢上依賴於所有的數據集,所以我們在設計上也需要儘量的規避全量 count
。
通常情況我們針對可預見的 count
查詢會做適當的緩存,可以是 Redis
,也可以是獨立的 MySQL
count
表。