標籤(空格分隔): MySQL5.7 COUNT()函數 探討html
細心的朋友會在平時工做和學習中,能夠看到MySQL的COUNT()函數有多種不一樣的參數,從而會有不一樣的統計方式,本文正是出於此目的一探究竟。mysql
辨析COUNT(*)、COUNT(1)、COUNT(0)、COUNT(列名)、COUNT(DISTINCT 列名)的區別和做用。sql
COUNT()函數用來統計表的行數,也就是統計記錄行數,很好理解。查看MySQL5.7官方手冊併發
官方對COUNT(expr)解釋:app
Returns a count of the number of non-NULL values of expr in the rows retrieved by a SELECT statement. The result is a BIGINT value. If there are no matching rows, COUNT() returns 0. COUNT(*) is somewhat different in that it returns a count of the number of rows retrieved, whether or not they contain NULL values. COUNT(DISTINCT expr,[expr...])Returns a count of the number of rows with different non-NULL expr values.If there are no matching rows, COUNT(DISTINCT) returns 0.
在SELECT檢索語句中,COUNT(expr)統計並返回參數expr爲非NULL值的總行數,COUNT(DISTINCT expr)返回的是參數expr爲非NULL值且不相同的總行數,結果是一個BIGINT數據類型的值,佔8個字節;若是沒有匹配到知足條件的行,結果返回0。可是**當expr不是具體的列,是COUNT(*)時會統計表中全部的行數,即便某些行是NULL也會被統計在內**。函數
新建測試表users性能
CREATE TABLE `users` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `LoginName` varchar(50) DEFAULT NULL, `LoginPwd` varchar(16) DEFAULT NULL, `Name` varchar(16) DEFAULT NULL, `Address` varchar(16) DEFAULT NULL, `Phone` varchar(16) DEFAULT NULL, `Mail` varchar(16) DEFAULT NULL, PRIMARY KEY (`Id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; #插入數據 mysql> select * from users; +----+------------+----------+------+----------+-------------+---------------+ | Id | LoginName | LoginPwd | Name | Address | Phone | Mail | +----+------------+----------+------+----------+-------------+---------------+ | 1 | bb1 | 123 | 張三 | 湖北武漢 | 13317190688 | 123@gmail.com | | 2 | bb3 | 123 | 李四 | 湖北武漢 | 13317190688 | 123@gmail.com | | 3 | jj4 | 123 | 張三 | 湖北武漢 | 13317190688 | 123@gmail.com | | 4 | kobeBryant | 123456 | NULL | LA | NULL | NULL | | 5 | kobe | 456 | NULL | NULL | NULL | NULL | | 6 | Jay | NULL | NULL | GXI | NULL | NULL | | 7 | jj4 | NULL | NULL | NULL | NULL | NULL | +----+------------+----------+------+----------+-------------+---------------+ 7 rows in set
執行查詢學習
mysql> SELECT COUNT(*),COUNT(1),COUNT(0),COUNT(-1), COUNT(LoginPwd),COUNT(Phone),COUNT(DISTINCT Phone) FROM users; +----------+----------+----------+-----------+-----------------+--------------+------------------------+ | COUNT(*) | COUNT(1) | COUNT(0) | COUNT(-1) | COUNT(LoginPwd) | COUNT(Phone) | COUNT(DISTINCT Phone) | +----------+----------+----------+-----------+-----------------+--------------+------------------------+ | 7 | 7 | 7 | 7 | 5 | 3 | 1 | +----------+----------+----------+-----------+-----------------+--------------+------------------------+ 1 row in set
根據上述結果能夠有如下結論:測試
對 COUNT(LoginPwd)、COUNT(Phone)和COUNT(DISTINCT Phone)的結果咱們不難理解,關鍵是要弄清楚COUNT(*)、COUNT(1)、COUNT(0)這三個式子,它們的使用區別是什麼,或者是沒區別。優化
查看官方文檔:
For MyISAM tables, COUNT(*) is optimized to return very quickly if the SELECT retrieves from one table, no other columns are retrieved, and there is no WHERE clause. This optimization only applies to MyISAM tables, because an exact row count is stored for this storage engine and can be accessed very quickly. COUNT(1) is only subject to the same optimization if the first column is defined as NOT NULL. For transactional storage engines such as InnoDB, storing an exact row count is problematic because multiple transactions may be occurring, each of which may affect the count.
mysql> explain SELECT COUNT(*),COUNT(1),COUNT(0),COUNT(-1), COUNT(LoginPwd),COUNT(Phone),COUNT( DISTINCT Phone) FROM users; +----+-------------+-------+------+---------------+------+---------+------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------+ | 1 | SIMPLE | users | ALL | NULL | NULL | NULL | NULL | 7 | NULL | +----+-------------+-------+------+---------------+------+---------+------+------+-------+ 1 row in set
執行整條語句的時候,能夠看到type字段是ALL,使用了全表掃描,表的行數是rows=7。
mysql> explain SELECT COUNT(*) FROM users; +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ | 1 | SIMPLE | users | index | NULL | PRIMARY | 4 | NULL | 7 | Using index | +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 1 row in set
執行COUNT(*)能夠看到type字段是index,沒有使用全表掃描,而是使用了索引優化查詢,使用了主鍵PRIMARY索引,表的行數是rows=7。
mysql> explain SELECT COUNT(1) FROM users; +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ | 1 | SIMPLE | users | index | NULL | PRIMARY | 4 | NULL | 7 | Using index | +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 1 row in set
執行COUNT(1)能夠看到type字段是index,沒有使用全表掃描,而是使用了索引優化查詢,使用了主鍵PRIMARY索引。
mysql> explain SELECT COUNT(0) FROM users; +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ | 1 | SIMPLE | users | index | NULL | PRIMARY | 4 | NULL | 7 | Using index | +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 1 row in set
執行COUNT(0)能夠看到type字段是index,沒有使用全表掃描,而是使用了索引優化查詢,使用了主鍵PRIMARY索引。
對於InnoDB,查詢COUNT(*)和COUNT(1)兩者並無區別,性能效率等效,都是全表掃描(有索引則會優化自動使用索引)。
InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.
序號 | 類別 | 做用 | 解釋說明 |
---|---|---|---|
1 | COUNT(*) | 統計總行數,含NULL值 | MyISAM引擎,若是沒有查詢其餘列且無WHERE語句會直接返回row count變量,高效。其餘狀況全表掃描(有索引則用索引),統計表的總行數。 |
2 | COUNT(n) | 統計總行數,能夠是COUNT(任何整數或小數),含NULL值 | 如COUNT(1),MyISAM引擎若是沒有查詢其餘列且無WHERE語句且第一列定義爲非NULL會直接返回row count變量,高效。其餘狀況全表掃描(有索引則用索引) |
3 | COUNT(列名) | 統計某一列非NULL的行數 | 純粹統計指定列的非NULL行數,不區分存儲引擎 |
4 | COUNT(DISTINCT 列名) | 統計某一列非NULL且不相同的行數 | 純粹統計指定列的非NULL且不相同的行數,不區分存儲引擎 |
使用選擇:
使用SUM(1)也能夠達到統計表總行數的目的,並且也包含NULL值,可是效率沒有COUNT(*)高。
參考: https://highdb.com/%E4%BA%86%E8%A7%A3-select-count-count1-%E5%92%8C-countfield/ 官方手冊:https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_count