其实就一个问题:count(1),count(*),count(主键),count(非主键字段)哪个更快?
于是建了一张测试表,插入了600多万条记录。表结构如下:
- CREATE TABLE `test` (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `c1` varchar(10) NOT NULL,
- `c2` varchar(10) NOT NULL,
- `c3` varchar(10) NOT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=6003060 DEFAULT CHARSET=utf8
看看下面三条sql:
下面是命令行下的执行情况:
- mysql> select count(1) from test;
- +----------+
- | count(1) |
- +----------+
- | 6003058 |
- +----------+
- 1 row in set (1.74 sec)
- mysql> select count(*) from test;
- +----------+
- | count(*) |
- +----------+
- | 6003058 |
- +----------+
- 1 row in set (1.75 sec)
- mysql> select count(id) from test;
- +-----------+
- | count(id) |
- +-----------+
- | 6003058 |
- +-----------+
- 1 row in set (1.87 sec)
- mysql> select count(c1) from test;
- +-----------+
- | count(c1) |
- +-----------+
- | 6003058 |
- +-----------+
- 1 row in set (2.02 sec)
从上面的执行时间看,前两条相差不多,第三条次之,最差的是第四条,看看explain的结果:
- mysql> explain select count(1) from test;
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
- | 1 | SIMPLE | test | index | NULL | PRIMARY | 4 | NULL | 6003369 | Using index |
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
- 1 row in set (0.00 sec)
- mysql> explain select count(*) from test;
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
- | 1 | SIMPLE | test | index | NULL | PRIMARY | 4 | NULL | 6003369 | Using index |
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
- 1 row in set (0.00 sec)
- mysql> explain select count(id) from test;
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
- | 1 | SIMPLE | test | index | NULL | PRIMARY | 4 | NULL | 6003369 | Using index |
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
- 1 row in set (0.00 sec)
- mysql> explain select count(c1) from test;
- +----+-------------+-------+------+---------------+------+---------+------+---------+-------+
- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
- +----+-------------+-------+------+---------------+------+---------+------+---------+-------+
- | 1 | SIMPLE | test | ALL | NULL | NULL | NULL | NULL | 6003369 | |
- +----+-------------+-------+------+---------------+------+---------+------+---------+-------+
- 1 row in set (0.00 sec)
由上可以看出,前三者的执行计划是一样的,第四条与前三者不同,没有使用覆盖索引,从执行时间上排序为:
count(1)=count(*) < count(主键) < count(非主键字段)
上面是未指定条件的情况,如果加上条件呢,看看下面三条语句:
下面是命令行下的执行情况:
- mysql> select count(1) from test where id>0;
- +----------+
- | count(1) |
- +----------+
- | 6003058 |
- +----------+
- 1 row in set (2.07 sec)
- mysql> select count(*) from test where id>0;
- +----------+
- | count(*) |
- +----------+
- | 6003058 |
- +----------+
- 1 row in set (2.07 sec)
- mysql> select count(id) from test where id>0;
- +-----------+
- | count(id) |
- +-----------+
- | 6003058 |
- +-----------+
- 1 row in set (2.07 sec)
- mysql> select count(c1) from test where id>0;
- +-----------+
- | count(c1) |
- +-----------+
- | 6003058 |
- +-----------+
- 1 row in set (2.28 sec)
从上面的执行时间可以看到:
再看一下explain的结果:
- mysql> explain select count(1) from test where id>0;
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+--------------------------+
- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+--------------------------+
- | 1 | SIMPLE | test | range | PRIMARY | PRIMARY | 4 | NULL | 3001684 | Using where; Using index |
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+--------------------------+
- 1 row in set (0.00 sec)
- mysql> explain select count(*) from test where id>0;
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+--------------------------+
- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+--------------------------+
- | 1 | SIMPLE | test | range | PRIMARY | PRIMARY | 4 | NULL | 3001684 | Using where; Using index |
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+--------------------------+
- 1 row in set (0.00 sec)
- mysql> explain select count(id) from test where id>0;
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+--------------------------+
- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+--------------------------+
- | 1 | SIMPLE | test | range | PRIMARY | PRIMARY | 4 | NULL | 3001684 | Using where; Using index |
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+--------------------------+
- 1 row in set (0.00 sec)
- mysql> explain select count(c1) from test where id>0;
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
- | 1 | SIMPLE | test | range | PRIMARY | PRIMARY | 4 | NULL | 3001684 | Using where |
- +----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
- 1 row in set (0.00 sec)
从上面的explain可以看到,前三种情况都会发生using index,即覆盖索引。
而最后的情况不会覆盖索引,会进行表读取,故速度会比前三者要慢,耗时更长就能理解了。
结论: