MySQL Count函數(shù)使用教程
COUNT 是一個(gè)匯總函數(shù)(聚集函數(shù)),它接受一個(gè)表達(dá)式作為參數(shù):
COUNT(expr)
COUNT函數(shù)用于統(tǒng)計(jì)在符合搜索條件的記錄中,指定的表達(dá)式expr不為NULL的行數(shù)有多少。這里需要特別注意的是,expr不僅僅可以是列名,其他任意表達(dá)式都是可以的。
一、COUNT 的使用
select COUNT(key1) FROM t;
這個(gè)語(yǔ)句是用于統(tǒng)計(jì)在 t 表 key1 列 值不為 NULL 的行數(shù)是多少。
看下面的這個(gè):
select COUNT('abc') FROM t;
這個(gè)語(yǔ)句是用于統(tǒng)計(jì)在 t 表的所有記錄中,‘abc’ 這個(gè)表達(dá)式不為 NULL的行數(shù)是多少。很顯然,‘abc’ 這個(gè)表達(dá)式永遠(yuǎn)不為 NULL, 所以上述語(yǔ)句其實(shí)就是統(tǒng)計(jì) t 表里有多少條記錄。
再看這個(gè):
select COUNT(*) from t;
這個(gè)語(yǔ)句就是直接統(tǒng)計(jì) t 表中有多少條記錄。
總結(jié) + 注意:COUNT函數(shù)的參數(shù)可以是任意表達(dá)式, 該函數(shù)用于統(tǒng)計(jì)在符合搜索條件的記錄中,指定的表達(dá)式不為NULL的行數(shù)有多少。
二、COUNT是怎么樣運(yùn)行的
mysql> select count(*) from single_table; +----------+ | count(*) | +----------+ | 12610 | +----------+ 1 row in set (0.00 sec) ####### single_table 表結(jié)構(gòu) ######## CREATE TABLE `single_table` ( `id` int NOT NULL AUTO_INCREMENT, `key1` varchar(100) DEFAULT NULL, `key2` int DEFAULT NULL, `key3` varchar(100) DEFAULT NULL, `key_part1` varchar(100) DEFAULT NULL, `key_part2` varchar(100) DEFAULT NULL, `key_part3` varchar(100) DEFAULT NULL, `common_field` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx_key2` (`key2`), KEY `idx_key1` (`key1`), KEY `idx_key3` (`key3`), KEY `idx_key_part` (`key_part1`,`key_part2`,`key_part3`) ) ENGINE=InnoDB AUTO_INCREMENT=20000 DEFAULT CHARSET=utf8mb3 |
這個(gè)語(yǔ)句是要去查詢(xún)表 single_table 中共包含多少條記錄。由于聚簇索引和二級(jí)索引中的記錄是一一對(duì)應(yīng)的,而二級(jí)索引記錄中包含的列是少于聚簇索引記錄的,所以同樣數(shù)量的二級(jí)索引記錄可以比聚簇索引記錄占用更少的存儲(chǔ)空間。如果我們使用二級(jí)索引執(zhí)行上述查詢(xún),即數(shù)一下idx_key2中共有多少條二級(jí)索引記錄(存在多個(gè)二級(jí)索引,為什么選擇idx_key2,下面會(huì)具體說(shuō)明),是比直接數(shù)聚簇索引中共有多少聚簇索引記錄可以節(jié)省很多I/O成本。所以?xún)?yōu)化器會(huì)決定使用idx_key2執(zhí)行上述查詢(xún)。
mysql> explain select count(*) from single_table; +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ | 1 | SIMPLE | single_table | NULL | index | NULL | idx_key2 | 5 | NULL | 12590 | 100.00 | Using index | +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
在執(zhí)行上述查詢(xún)時(shí),server層會(huì)維護(hù)一個(gè)名叫count的變量,然后:
(1)server層向InnoDB要第一條記錄。
(2)InnoDB找到idx_key1的第一條二級(jí)索引記錄,并返回給server層(注意:由于此時(shí)只是統(tǒng)計(jì)記錄數(shù)量,所以并不需要回表)。
(3)由于COUNT函數(shù)的參數(shù)是*,MySQL會(huì)將*當(dāng)作常數(shù)0處理。由于0并不是NULL,server層給count變量加1。
(4)server層向InnoDB要下一條記錄。
(5)InnoDB通過(guò)二級(jí)索引記錄的next_record屬性找到下一條二級(jí)索引記錄,并返回給server層。
(6)server層繼續(xù)給count變量加1。
(7)... 重復(fù)上述過(guò)程,直到InnoDB向server層返回沒(méi)記錄可查的消息。
(8)server層將最終的count變量的值發(fā)送到客戶(hù)端。
三、COUNT函數(shù)的索引使用情況
下面我們?cè)鰧?duì) count(*),count(1),count(常數(shù)),count(主鍵列),count(普通列(有索引)),count(普通列(無(wú)索引))
(1)count(*),count(1),count(常數(shù))
mysql> show create table single_table; +--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | single_table | CREATE TABLE `single_table` ( `id` int NOT NULL AUTO_INCREMENT, `key1` varchar(100) DEFAULT NULL, `key2` int DEFAULT NULL, `key3` varchar(100) DEFAULT NULL, `key_part1` varchar(100) DEFAULT NULL, `key_part2` varchar(100) DEFAULT NULL, `key_part3` varchar(100) DEFAULT NULL, `common_field` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx_key2` (`key2`), KEY `idx_key1` (`key1`), KEY `idx_key3` (`key3`), KEY `idx_key_part` (`key_part1`,`key_part2`,`key_part3`) ) ENGINE=InnoDB AUTO_INCREMENT=20000 DEFAULT CHARSET=utf8mb3 | +--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) mysql> select count(*) from single_table; +----------+ | count(*) | +----------+ | 12610 | +----------+ 1 row in set (0.00 sec) ## count(*) 采用了 idx_key2 索引 mysql> explain select count(*) from single_table; +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ | 1 | SIMPLE | single_table | NULL | index | NULL | idx_key2 | 5 | NULL | 12590 | 100.00 | Using index | +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) ## count(1) 采用了 idx_key2 索引 mysql> explain select count(1) from single_table; +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ | 1 | SIMPLE | single_table | NULL | index | NULL | idx_key2 | 5 | NULL | 12590 | 100.00 | Using index | +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) ## count('abc') 采用了 idx_key2 索引 mysql> explain select count('abc') from single_table; +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ | 1 | SIMPLE | single_table | NULL | index | NULL | idx_key2 | 5 | NULL | 12590 | 100.00 | Using index | +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
通過(guò)上述查詢(xún)結(jié)果可以看出:
count(*)、count(1)、count('abc') 均采用了 idx_key2,而索引idx_key2 對(duì)應(yīng)的索引列為 key2,字段類(lèi)型為 int,占用空間為最小的索引列。
結(jié)論:
對(duì)于 COUNT(*)、COUNT(1) 或者任意的 COUNT(常數(shù)) 來(lái)說(shuō),讀取哪個(gè)索引的記錄其實(shí)并不重要,因?yàn)閟erver層只關(guān)心存儲(chǔ)引擎是否讀到了記錄,而并不需要從記錄中提取指定的字段來(lái)判斷是否為NULL。所以?xún)?yōu)化器會(huì)使用占用存儲(chǔ)空間最小的那個(gè)索引來(lái)執(zhí)行查詢(xún)。
(2)count(主鍵列)
## count(id) 采用了 idx_key2 索引 mysql> explain select count(id) from single_table; +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ | 1 | SIMPLE | single_table | NULL | index | NULL | idx_key2 | 5 | NULL | 12590 | 100.00 | Using index | +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
通過(guò)上述查詢(xún)結(jié)果可以看出:
count(id)采用了 idx_key2,而索引idx_key2 對(duì)應(yīng)的索引列為 key2,字段類(lèi)型為 int,占用空間為最小的索引列。
結(jié)論:
對(duì)于 COUNT(id) 來(lái)說(shuō),由于id是主鍵,不論是聚簇索引記錄,還是任意一個(gè)二級(jí)索引記錄中都會(huì)包含主鍵字段,所以其實(shí)讀取任意一個(gè)索引中的記錄都可以獲取到id字段,此時(shí)優(yōu)化器也會(huì)選擇占用空間最小的那個(gè)索引來(lái)執(zhí)行查詢(xún)。
(3)count(普通列(有索引))
## count('key1') 采用了 idx_key1 索引 mysql> explain select count(key1) from single_table; +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ | 1 | SIMPLE | single_table | NULL | index | NULL | idx_key1 | 303 | NULL | 12590 | 100.00 | Using index | +----+-------------+--------------+------------+-------+---------------+----------+---------+------+-------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) ## count(common_field) 未采用任何索引 mysql> explain select count(common_field) from single_table; +----+-------------+--------------+------------+------+---------------+------+---------+------+-------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+--------------+------------+------+---------------+------+---------+------+-------+----------+-------+ | 1 | SIMPLE | single_table | NULL | ALL | NULL | NULL | NULL | NULL | 12590 | 100.00 | NULL | +----+-------------+--------------+------------+------+---------------+------+---------+------+-------+----------+-------+ 1 row in set, 1 warning (0.00 sec)
通過(guò)上述查詢(xún)結(jié)果可以看出:
count(key1)采用了 idx_key1,索引idx_key1對(duì)應(yīng)的索引列即為key1。count(common_field)未采用任何索引,common_field也不存在任何索引。
結(jié)論:
對(duì)于COUNT(非主鍵列)來(lái)說(shuō),我們指定的列可能并不會(huì)包含在每一個(gè)索引中。這樣優(yōu)化器只能選擇包含我們指定的列的索引去執(zhí)行查詢(xún),這就可能導(dǎo)致優(yōu)化器選擇的索引并不是最小的那個(gè)。
四、補(bǔ)充
對(duì)于count(非空普通列)來(lái)說(shuō),使用索引情況會(huì)怎么樣?會(huì)不會(huì)直接采用最小占用空間索引呢?
mysql> show create table person_info; +-------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | person_info | CREATE TABLE `person_info` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL, `birthday` date NOT NULL, `age` int DEFAULT NULL, `phone_number` char(11) NOT NULL, `country` varchar(100) NOT NULL, PRIMARY KEY (`id`), KEY `idx_name` (`name`), KEY `idx_age` (`age`) ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb3 | +-------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) mysql> explain select count(phone_number) from person_info; +----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------+ | 1 | SIMPLE | person_info | NULL | ALL | NULL | NULL | NULL | NULL | 9 | 100.00 | NULL | +----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------+ 1 row in set, 1 warning (0.00 sec)
通過(guò)上述查詢(xún)結(jié)果可以看出:
雖然 phone_number 字段為 not null,count(phone_number) 和 count(*) 結(jié)果一致,但是 phone_number 仍然并有選擇走索引。
五、總結(jié)
(1)對(duì)于COUNT(*)、COUNT(常數(shù))、COUNT(主鍵) 形式的COUNT函數(shù)來(lái)說(shuō),優(yōu)化器可以選擇最小索引執(zhí)行查詢(xún),從而提升效率,它們的執(zhí)行過(guò)程是一樣的,只不過(guò)在判斷表達(dá)式是否為NULL時(shí)選擇不同的判斷方式,這個(gè)判斷為NULL的過(guò)程的代價(jià)可以忽略不計(jì),所以我們可以認(rèn)為 COUNT(*)、COUNT(常數(shù))、COUNT(主鍵) 所需要的代價(jià)是相同的。
(2)對(duì)于 COUNT(非主鍵列) 來(lái)說(shuō),server層必須要從InnoDB中讀到包含非主鍵列的記錄,所以?xún)?yōu)化器并不能隨心所欲的選擇占用空間最小的索引去執(zhí)行。
到此這篇關(guān)于MySQL Count函數(shù)使用教程的文章就介紹到這了,更多相關(guān)MySQL Count內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mysql之如何創(chuàng)建函數(shù)問(wèn)題
這篇文章主要介紹了Mysql之如何創(chuàng)建函數(shù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03手把手教你使用Navicat查詢(xún)表的詳細(xì)結(jié)構(gòu)
在使用Navicat時(shí),我們可以通過(guò)執(zhí)行一些SQL語(yǔ)句來(lái)查看表結(jié)構(gòu),下面這篇文章主要給大家介紹了關(guān)于如何使用Navicat查詢(xún)表的詳細(xì)結(jié)構(gòu),文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05Mysql 5.7.20壓縮版下載和安裝簡(jiǎn)易教程
這篇文章主要介紹了Mysql 5.7.20壓縮版下載和安裝簡(jiǎn)易教程,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-11-11Mysql數(shù)據(jù)類(lèi)型與CRUD操作詳細(xì)講解
這篇文章主要介紹了Mysql數(shù)據(jù)類(lèi)型與CRUD操作,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-10-10MySQL explain獲取查詢(xún)指令信息原理及實(shí)例
這篇文章主要介紹了MySQL explain獲取查詢(xún)指令信息原理及實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05Mysql 查詢(xún)JSON結(jié)果的相關(guān)函數(shù)匯總
這篇文章主要介紹了Mysql 查詢(xún) JSON 結(jié)果的相關(guān)函數(shù)匯總,幫助大家更好的理解和使用MySQL,感興趣的朋友可以了解下2020-11-11