MySQL count(*)原理


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(*)函數的優化)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM