MySQL之count探究

count()功能:

1汞斧、統(tǒng)計某個列的值的數(shù)量滔驶,在統(tǒng)計列值時要求列值是非空的(不統(tǒng)計NULL)即:在COUNT()的括號中指定了列或者列表達(dá)式遇革,則統(tǒng)計的就是這個列或者表達(dá)式有值的結(jié)果數(shù)。

2揭糕、統(tǒng)計結(jié)果集的行數(shù)萝快,當(dāng)確認(rèn)括號內(nèi)的表達(dá)式值不可能為空時,實際上就是在統(tǒng)計行數(shù)著角,例如:當(dāng)使用COUNT()的時候揪漩,這種情況下通配符并不像我們猜想的那樣擴(kuò)展成所有的列,實際上會忽略所有列而直接統(tǒng)計所有的行數(shù)

  • 如果該表只有一個主鍵索引吏口,沒有任何二級索引的情況下奄容,那么COUNT(*)和COUNT(1)都是通過通過主鍵索引來統(tǒng)計行數(shù)的
  • 如果該表有二級索引,則COUNT(1)和COUNT(*)都會通過占用空間最小的字段的二級索引進(jìn)行統(tǒng)計

count(主鍵):

  • innodb會遍歷整張表产徊,把每一行的id都取處理昂勒,返回給server層(8.0這里有所改進(jìn)不是一行一行返回),server層拿到id后判斷是不可能為null的就按行累加舟铜;

count(1):

  • innodb會遍歷整張表,但不取值戈盈。server層對返回的每一行,放進(jìn)去一個數(shù)字“1”判斷是不可能為null的就按行累加谆刨;

count(字段):

  • 如果這個“字段”定義為 not null 的話塘娶,一行行地從記錄里面讀出這個字段按行累加;
  • 如果這個“字段”定義允許為 null痴荐,執(zhí)行的時候判斷到有可能是 null,還要把值取出來再判斷一下官册,不是 null 才累加生兆。

count(*) :

  • 并不會把全部字段取出來,而是專門做了優(yōu)化,不取值鸦难,按行累加

綜上:若要比較四者的不同根吁,可簡單給出如下結(jié)論:

count(字段)<count(主鍵)<count(1)≈count(*)

https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_count

執(zhí)行計劃

對不同執(zhí)行方法執(zhí)行完成重啟mysqld- server排除緩存干擾

測試過程

-- 測試表
CREATE TABLE `test_count` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `col1` char(50) NOT NULL,
  `col2` varchar(50) DEFAULT NULL,
  `col3` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4
 
-- 錄入數(shù)據(jù)
DELIMITER $$
DROP PROCEDURE IF EXISTS `bucket_insert`$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `bucket_insert`()
BEGIN
  DECLARE i INT;
  SET i =0;
  SET AUTOCOMMIT=0; 
  WHILE i < 10000000 DO
  IF i MOD 2 = 0 THEN
  INSERT INTO test_count (col1,col2,col3) VALUES (MD5(RAND()*1000),NULL,RAND()*500);
  ELSE
    INSERT INTO test_count (col1,col2,col3) VALUES (MD5(RAND()*1000),MD5(RAND()*3000),RAND()*500);
  END IF;
  SET i = i + 1;
  END WHILE;
  COMMIT;
  END$$
DELIMITER ;
 
-- 執(zhí)行計劃,只有主鍵索引
 
root@[test]> explain select count(*) from test_count;
+----+-------------+------------+-------+---------------+---------+---------+------+---------+-------------+
| id | select_type | table      | type  | possible_keys | key     | key_len | ref  | rows    | Extra       |
+----+-------------+------------+-------+---------------+---------+---------+------+---------+-------------+
|  1 | SIMPLE      | test_count | index | NULL          | PRIMARY | 4       | NULL | 9694550 | Using index |
+----+-------------+------------+-------+---------------+---------+---------+------+---------+-------------+
1 row in set (0.02 sec)
 
root@[test]> explain select count(1) from test_count;
+----+-------------+------------+-------+---------------+---------+---------+------+---------+-------------+
| id | select_type | table      | type  | possible_keys | key     | key_len | ref  | rows    | Extra       |
+----+-------------+------------+-------+---------------+---------+---------+------+---------+-------------+
|  1 | SIMPLE      | test_count | index | NULL          | PRIMARY | 4       | NULL | 9694550 | Using index |
+----+-------------+------------+-------+---------------+---------+---------+------+---------+-------------+
1 row in set (0.00 sec)
 
root@[test]> explain select count(id) from test_count; 
+----+-------------+------------+-------+---------------+---------+---------+------+---------+-------------+
| id | select_type | table      | type  | possible_keys | key     | key_len | ref  | rows    | Extra       |
+----+-------------+------------+-------+---------------+---------+---------+------+---------+-------------+
|  1 | SIMPLE      | test_count | index | NULL          | PRIMARY | 4       | NULL | 9694550 | Using index |
+----+-------------+------------+-------+---------------+---------+---------+------+---------+-------------+
1 row in set (0.00 sec)
 
root@[test]> explain select count(col1) from test_count;   
+----+-------------+------------+------+---------------+------+---------+------+---------+-------+
| id | select_type | table      | type | possible_keys | key  | key_len | ref  | rows    | Extra |
+----+-------------+------------+------+---------------+------+---------+------+---------+-------+
|  1 | SIMPLE      | test_count | ALL  | NULL          | NULL | NULL    | NULL | 9694550 | NULL  |
+----+-------------+------------+------+---------------+------+---------+------+---------+-------+
 
-- 執(zhí)行計劃合蔽,存在二級索引,可以看出一下三種count都會選擇索引length最短的索引掃描
root@[test]> explain select count(id) from test_count;    
+----+-------------+------------+-------+---------------+----------+---------+------+---------+-------------+
| id | select_type | table      | type  | possible_keys | key      | key_len | ref  | rows    | Extra       |
+----+-------------+------------+-------+---------------+----------+---------+------+---------+-------------+
|  1 | SIMPLE      | test_count | index | NULL          | idx_col1 | 200     | NULL | 9694550 | Using index |
+----+-------------+------------+-------+---------------+----------+---------+------+---------+-------------+
1 row in set (0.00 sec)
 
root@[test]> explain select count(*) from test_count; 
+----+-------------+------------+-------+---------------+----------+---------+------+---------+-------------+
| id | select_type | table      | type  | possible_keys | key      | key_len | ref  | rows    | Extra       |
+----+-------------+------------+-------+---------------+----------+---------+------+---------+-------------+
|  1 | SIMPLE      | test_count | index | NULL          | idx_col1 | 200     | NULL | 9694550 | Using index |
+----+-------------+------------+-------+---------------+----------+---------+------+---------+-------------+
1 row in set (0.00 sec)
 
root@[test]> explain select count(1) from test_count;
+----+-------------+------------+-------+---------------+----------+---------+------+---------+-------------+
| id | select_type | table      | type  | possible_keys | key      | key_len | ref  | rows    | Extra       |
+----+-------------+------------+-------+---------------+----------+---------+------+---------+-------------+
|  1 | SIMPLE      | test_count | index | NULL          | idx_col1 | 200     | NULL | 9694550 | Using index |
+----+-------------+------------+-------+---------------+----------+---------+------+---------+-------------+
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末击敌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子拴事,更是在濱河造成了極大的恐慌沃斤,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刃宵,死亡現(xiàn)場離奇詭異衡瓶,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)牲证,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進(jìn)店門哮针,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人坦袍,你說我怎么就攤上這事十厢。” “怎么了捂齐?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵蛮放,是天一觀的道長。 經(jīng)常有香客問我辛燥,道長筛武,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任挎塌,我火速辦了婚禮徘六,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘榴都。我一直安慰自己待锈,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布嘴高。 她就那樣靜靜地躺著竿音,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拴驮。 梳的紋絲不亂的頭發(fā)上春瞬,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天,我揣著相機(jī)與錄音套啤,去河邊找鬼宽气。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的萄涯。 我是一名探鬼主播绪氛,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼涝影!你這毒婦竟也來了枣察?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤燃逻,失蹤者是張志新(化名)和其女友劉穎序目,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體唆樊,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡宛琅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了逗旁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嘿辟。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖片效,靈堂內(nèi)的尸體忽然破棺而出红伦,到底是詐尸還是另有隱情,我是刑警寧澤淀衣,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布昙读,位于F島的核電站,受9級特大地震影響膨桥,放射性物質(zhì)發(fā)生泄漏蛮浑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一只嚣、第九天 我趴在偏房一處隱蔽的房頂上張望沮稚。 院中可真熱鬧,春花似錦册舞、人聲如沸蕴掏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盛杰。三九已至,卻和暖如春藐石,著一層夾襖步出監(jiān)牢的瞬間即供,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工于微, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留逗嫡,地道東北人办素。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像祸穷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子勺三,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,678評論 2 354

推薦閱讀更多精彩內(nèi)容