前言
基本職場上的程式員用來統計資料庫表的行數都會使用count(*),count(1)或者count(主鍵),那么它們之間的區別和性能你又是否了解呢?
其實程式員在開發的程序中,在一張大表上統計總行數是非常耗時的一個操作,那么我們應該用哪個方法統計會更快呢?
接下來我們就來聊一聊MySQL中統計總行數的方法和性能,
count(*),count(1),count(主鍵)哪個更快?
1、建表并且插入1000萬條資料進行實驗測驗:
# 創建測驗表
CREATE TABLE `t6` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`status` tinyint(4) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# 創建存盤程序插入1000w資料
CREATE PROCEDURE insert_1000w()
BEGIN
DECLARE i INT;
SET i=1;
WHILE i<=10000000 DO
INSERT INTO t6(name,status) VALUES('god-jiang-666',1);
SET i=i+1;
END WHILE;
END;
#呼叫存盤程序,插入1000萬行資料
call insert_1000w();
2、分析實驗結果
# 花了0.572秒
select count(*) from t6;

# 花了0.572秒
select count(1) from t6;

# 花了0.580秒
select count(id) from t6;

# 花了0.620秒
select count(*) from t6 force index (primary);

從上面的實驗我們可以得出,count(*)和count(1)是最快的,其次是count(id),最慢的是count使用了強制主鍵的情況,
下面我們繼續測驗一下它們各自的執行計劃:
explain select count(*) from t6;
show warnings;


explain select count(1) from t6;
show warnings;


explain select count(id) from t6;
show warnings;


explain select count(*) from t6 force index (primary);
show warnings;


從上面的實驗可以得出這三點:
- count(*)被MySQL查詢優化器改寫成了count(0),并選擇了idx_status索引
- count(1)和count(id)都選擇了idx_statux索引
- 加了force index(primary)之后,走了強制索引
這個idx_status就是相當于是二級輔助索引樹,目的就是為了說明: InnoDB在處理count(*)的時候,有輔助索引樹的情況下,會優先選擇輔助索引樹來統計總行數,
為了驗證count(*)會優先選擇輔助索引樹這個結論,我們繼續來看看下面的實驗:
# 洗掉idx_status索引,繼續執行count(*)
alter table t6 drop index idx_status;
explain select count(*) from t6;

從以上實驗可以得出,洗掉了idx_status這個輔助索引樹,count(*)就會選擇走主鍵索引,所以結論:count(*)會優先選擇輔助索引,假如沒有輔助索引的存在,就會走主鍵索引,
為什么count(*)會優先選擇輔助索引?
在MySQL5.7.18之前,InnoDB通過掃描聚集索引來處理count(*)陳述句,
從MySQL5.7.18開始,InnoDB通過遍歷最小的可用二級索引來處理count(*)陳述句,如果不存在二級索引,則掃描聚集索引,
新版本為何會使用二級索引來處理count(*)呢?
因為InnoDB二級索引樹的葉子節點上存放的是主鍵,而主鍵索引樹的葉子節點存放的是整行資料,所以二級索引樹比主鍵索引樹小,因此查詢優化器基于成本考慮,優先選擇的是二級索引,所以索引count(*)快于count(主鍵),
總結
這篇文章的結論就是count(*)=count(1)>count(id),
為什么count(id)走了主鍵索引還會更慢呢?因為count(id)需要取出主鍵,然后判斷不為空,再累加,代價更高,
count(*)是會總計出所有NOT NULL和NULL的欄位,而count(id)是不會統計NULL欄位的,所以我們在建表的盡量使用NOT NULL并且給它一個默認是空即可,
最后,在以后總計資料庫表的總行數的時候,可以大膽的使用count(*)或者count(1),
參考資料
- 《高性能MySQL》(第三版)第六章優化COUNT()查詢
- 《MySQL實戰45講》林曉斌
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/223774.html
標籤:其他
下一篇:webpack使用
