mysql count(*)原理
1 2 3 4 5 6
|
create table t1( c1 varchar(30) not null, c2 varchar(20) not null, c3 varchar(40) not null, c4 varchar(10) not null ) engine=innodb;
|
1. 表無任何索引
不含任何索引,則執行全表掃描(ALL)
1 2 3 4 5 6 7
|
mysql> explain select count(*) from t1; +----+-------------+-------+------+---------------+------+---------+------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------+ | 1 | SIMPLE | t1 | ALL | NULL | NULL | NULL | NULL | 1 | | +----+-------------+-------+------+---------------+------+---------+------+------+-------+ 1 row in set (0.00 sec)
|
2. 表有主鍵
使用主鍵進行掃描
1 2 3 4 5 6 7 8 9
|
mysql> alter table t1 add primary key (c1);
mysql> explain select count(*) from t1; +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ | 1 | SIMPLE | t1 | index | NULL | PRIMARY | 32 | NULL | 1 | Using index | +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 1 row in set (0.00 sec)
|
3. 表有二級索引
不管二級索引的key_len是否小於主鍵,都使用二級索引
1 2 3 4 5 6 7 8 9
|
mysql> alter table t1 add index i1(c3);
mysql> explain select count(*) from t1; +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | t1 | index | NULL | i1 | 42 | NULL | 1 | Using index | +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+ 1 row in set (0.00 sec)
|
4. 表有多個二級索引
使用key_len小的二級索引
1 2 3 4 5 6 7 8 9
|
mysql> alter table t1 add index i2(c4);
mysql> explain select count(*) from t1; +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | t1 | index | NULL | i2 | 12 | NULL | 1 | Using index | +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+ 1 row in set (0.00 sec)
|
5. MyISAM與InnoDB
正如在不同的存儲引擎中,count()函數的執行是不同的。
- 在MyISAM存儲引擎中,count()函數是直接讀取數據表保存的行記錄數並返回
- 在InnoDB存儲引擎中,count(*)函數是先從內存中讀取表中的數據到內存緩沖區,然后掃描全表獲得行記錄數的。
在使用count函數中加上where條件時,在兩個存儲引擎中的效果是一樣的,都會掃描全表計算某字段有值項的次數。
6. 聚簇索引
- 如果您的表上定義有主鍵,該主鍵索引是聚集索引。
- 如果你不定義為您的表的主鍵時,MySQL取第一個唯一索引(unique)而且只含非空列(NOT NULL)作為主鍵,InnoDB使用它作為聚集索引。
- 如果沒有這樣的列,InnoDB就自己產生一個這樣的ID值,
優先選index key_len小的索引進行count(*),盡量不使用聚簇索引
7. 說明
- count(column)不會計算column為NULL的列
- 通過infomation_schema可以快速拿到表的count值,但不是一個准確的值
- myISAM會存儲具體的行數(可能因為myISAM事務要加表鎖,才這樣設計),innodb則需要進行全表掃描
8. 參考資料
在MySQL的InnoDB存儲引擎中count(*)函數的優化)