转自 http://www.2cto.com/database/201508/433975.html

mysqlcount(*)会选哪个索引?
2015-08-19      0个评论    来源:Database、Code  
收藏    我要投稿
 

今天在查询一个表行数的时候,发现count(1)和count(*)执行效率居然是一样的。这跟Oracle还是有区别的。遂查看两种方式的执行计划:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
mysql> select count(1) from customer;
+----------+
| count(1) |
+----------+
|   150000 |
+----------+
1 row in set (0.03 sec)
 
mysql> flush tables;
Query OK, 0 rows affected (0.00 sec)
 
mysql> select count(*) from customer;
+----------+
| count(*) |
+----------+
|   150000 |
+----------+
1 row in set (0.03 sec)

查看执行计划:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
mysql> explain select count(1) from customer;
+----+-------------+----------+-------+---------------+---------------+---------+------+--------+-------------+
| id | select_type | table    | type  | possible_keys | key           | key_len | ref  | rows   | Extra       |
+----+-------------+----------+-------+---------------+---------------+---------+------+--------+-------------+
|  1 | SIMPLE      | customer | index | NULL          | i_c_nationkey | 5       | NULL | 151191 | Using index |
+----+-------------+----------+-------+---------------+---------------+---------+------+--------+-------------+
1 row in set (0.00 sec)
 
mysql> explain select count(*) from customer;
+----+-------------+----------+-------+---------------+---------------+---------+------+--------+-------------+
| id | select_type | table    | type  | possible_keys | key           | key_len | ref  | rows   | Extra       |
+----+-------------+----------+-------+---------------+---------------+---------+------+--------+-------------+
|  1 | SIMPLE      | customer | index | NULL          | i_c_nationkey | 5       | NULL | 151191 | Using index |
+----+-------------+----------+-------+---------------+---------------+---------+------+--------+-------------+
1 row in set (0.00 sec)
 
mysql> show index from customer;
+----------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table    | Non_unique | Key_name      | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| customer |          0 | PRIMARY       |            1 | c_custkey   | A         |      150525 |     NULL | NULL   |      | BTREE      |         |               |
| customer |          1 | i_c_nationkey |            1 | c_nationkey | A         |          47 |     NULL | NULL   | YES  | BTREE      |         |               |
+----------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.08 sec)

发现不管是count(1)或count(*)都是走的i_c_nationkey这个索引。平时我们检索数据的时候肯定是主键索引效率高,那么我们强制主键索引来看看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mysql> select count(*) from customer force index(PRIMARY);
+----------+
| count(*) |
+----------+
|   150000 |
+----------+
1 row in set (0.68 sec)
mysql> explain select count(*) from customer force index(PRIMARY);
+----+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+
| id | select_type | table    | type  | possible_keys | key     | key_len | ref  | rows   | Extra       |
+----+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+
|  1 | SIMPLE      | customer | index | NULL          | PRIMARY | 4       | NULL | 150525 | Using index |
+----+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+
1 row in set (0.00 sec)

可以看到走主键索引的时候效率比较差。那么是为什么呢。
平时我们检索一列的时候,基本上等值或范围查询,那么索引基数大的索引必然效率很高。但是在做count(*)的时候并没有检索具体的一行或者一个范围。那么选择基数小的索引对
count操作效率会更高。在做count操作的时候,mysql会遍历每个叶子节点,所以基数越小,效率越高。mysql非聚簇索引叶子节点保存的主键ID,所以需要检索两遍索引。但是这里相对于遍历主键索引。及时检索两遍索引效率也比单纯的检索主键索引快。
那么再以一个表作为证明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
mysql> explain select count(*) from lineitem;
+----+-------------+----------+-------+---------------+--------------+---------+------+---------+-------------+
| id | select_type | table    | type  | possible_keys | key          | key_len | ref  | rows    | Extra       |
+----+-------------+----------+-------+---------------+--------------+---------+------+---------+-------------+
|  1 | SIMPLE      | lineitem | index | NULL          | i_l_shipdate | 4       | NULL | 6008735 | Using index |
+----+-------------+----------+-------+---------------+--------------+---------+------+---------+-------------+
1 row in set (0.00 sec)
 
mysql> show index from lineitem;
+----------+------------+-----------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table    | Non_unique | Key_name              | Seq_in_index | Column_name   | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+-----------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| lineitem |          0 | PRIMARY               |            1 | l_orderkey    | A         |     2997339 |     NULL | NULL   |      | BTREE      |         |               |
| lineitem |          0 | PRIMARY               |            2 | l_linenumber  | A         |     5994679 |     NULL | NULL   |      | BTREE      |         |               |
| lineitem |          1 | i_l_shipdate          |            1 | l_shipDATE    | A         |        5208 |     NULL | NULL   | YES  | BTREE      |         |               |
| lineitem |          1 | i_l_suppkey_partkey   |            1 | l_partkey     | A         |      428191 |     NULL | NULL   | YES  | BTREE      |         |               |
| lineitem |          1 | i_l_suppkey_partkey   |            2 | l_suppkey     | A         |     1998226 |     NULL | NULL   | YES  | BTREE      |         |               |
| lineitem |          1 | i_l_partkey           |            1 | l_partkey     | A         |      461129 |     NULL | NULL   | YES  | BTREE      |         |               |
| lineitem |          1 | i_l_suppkey           |            1 | l_suppkey     | A         |       19213 |     NULL | NULL   | YES  | BTREE      |         |               |
| lineitem |          1 | i_l_receiptdate       |            1 | l_receiptDATE | A         |          17 |     NULL | NULL   | YES  | BTREE      |         |               |
| lineitem |          1 | i_l_orderkey          |            1 | l_orderkey    | A         |     2997339 |     NULL | NULL   |      | BTREE      |         |               |
| lineitem |          1 | i_l_orderkey_quantity |            1 | l_orderkey    | A         |     1998226 |     NULL | NULL   |      | BTREE      |         |               |
| lineitem |          1 | i_l_orderkey_quantity |            2 | l_quantity    | A         |     5994679 |     NULL | NULL   | YES  | BTREE      |         |               |
| lineitem |          1 | i_l_commitdate        |            1 | l_commitDATE  | A         |        7836 |     NULL | NULL   | YES  | BTREE      |         |               |
+----------+------------+-----------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
12 rows in set (0.96 sec)

这里一看l_shipDATE并不是基数最小的呀,殊不知这个统计信息是不准确的。我们用sql看一下。

1
2
3
4
5
6
7
mysql> select count(distinct(l_shipDATE)) from lineitem;
+-----------------------------+
| count(distinct(l_shipDATE)) |
+-----------------------------+
|                        2526 |
+-----------------------------+
1 row in set (0.01 sec)

那么比他小的那些列呢?

1
2
3
4
5
6
7
mysql> select count(distinct(l_receiptDATE)) from lineitem;
+--------------------------------+
| count(distinct(l_receiptDATE)) |
+--------------------------------+
|                           2554 |
+--------------------------------+
1 row in set (0.01 sec)

其他就不看了,这里再次说明mysql选择了基数小的索引。

1226关于count(*)不走主键索引反而走二级索引的更多相关文章

  1. mysql InnoDB index 主键采用聚簇索引,二级索引不采用聚簇索引

    原文链接 我的归纳: (1)InnoDB的主键采用聚簇索引存储,使用的是B+Tree作为索引结构,但是叶子节点存储的是索引值和数据本身(注意和MyISAM的不同). (2)InnoDB的二级索引不使用 ...

  2. 【mysql优化】mysql count(*)、count(1)、count(主键字段)、count(非主键字段)哪个性能最佳

    测试结果为:count(*)和count(1)基本相等,count(非主键字段)最耗性能 -- 数据量 708254select count(*) from tmp_test1;-- avg 0.22 ...

  3. Oracle删除主键约束的同时删除索引

    继续昨天的折腾(Oracle修改主键约束),删掉主键约束后,发现唯一索引并未删掉.仔细看了下,主键约束跟唯一索引名称不一样,这说明是先创建了唯一索引,后创建的主键约束.我们来试验下: SQL> ...

  4. 主键primary key和唯一索引unique index

    1)主键一定是唯一性索引,唯一性索引并不一定就是主键. 2)主键就是能够唯一标识表中某一行的属性或属性组,一个表只能有一个主键,但可以有多个候选索引. 3)主键常常与外键构成参照完整性约束,防止出现数 ...

  5. mysql 主键和默认 设为索引的规则

    一.mysql 表中如果是单主键的话,那这个主键也会被 系统默认建为 索引 二.mysql 表中如果是复合主键的话,那系统会遵循左对齐原则,即如复合主键 a 和 b字段和c字段..., 默认建的主键索 ...

  6. MySQL 聚簇索引&&二级索引&&辅助索引

    MySQL非聚簇索引&&二级索引&&辅助索引 mysql中每个表都有一个聚簇索引(clustered index ),除此之外的表上的每个非聚簇索引都是二级索引,又叫辅 ...

  7. COUNT(*)、COUNT(主键)、COUNT(1)

    MyISAM引擎,记录数是结构的一部分,已存cache在内存中; InnoDB引擎,需要重新计算,id是主键的话,会加快扫描速度: 所以select count(*)  MyISAM完胜! MyISA ...

  8. 图解MySQL:count(*) 、count(1) 、count(主键字段)、count(字段)哪个性能最好?

    大家好,我是小林. 当我们对一张数据表中的记录进行统计的时候,习惯都会使用 count 函数来统计,但是 count 函数传入的参数有很多种,比如 count(1).count(*).count(字段 ...

  9. MySQL的几个概念:主键,外键,索引,唯一索引

    概念: 主键(primary key) 能够唯一标识表中某一行的属性或属性组.一个表只能有一个主键,但可以有多个候选索引.主键常常与外键构成参照完整性约束,防止出现数据不一致.主键可以保证记录的唯一和 ...

随机推荐

  1. 利用js取到下拉框中选择的值

    现在的需求是:下拉框中要是选择加盟商让其继续选择学校,要是选择平台管理员则不需要选择学校.隐藏选择下拉列表. 选择枚举值: /// <summary> /// 平台角色 /// </ ...

  2. StackExchange.Redis帮助类解决方案RedisRepository封装(散列Hash类型数据操作)

    本文版权归博客园和作者本人共同所有,转载和爬虫请注明本系列分享地址:http://www.cnblogs.com/tdws/p/5815735.html 上一篇文章的不合理之处,已经有所修改. 今天分 ...

  3. Qt信号与槽自动关联机制

    参考链接1:http://blog.csdn.net/skyhawk452/article/details/6121407 参考链接2:http://blog.csdn.net/memory_exce ...

  4. 2016年最新mac下vscode配置golang开发环境支持debug

    网上目前还找不到完整的mac下golang环境配置支持,本人配置成功,现在整理分享出来. mac最好装下xcode,好像有依赖关系安装Homebrew打开终端窗口, 粘贴脚本执行/usr/bin/ru ...

  5. 来玩Play框架02 响应

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我上一章总结了Play框架的基本使用.这一章里,我将修改和增加响应. HTTP协议 ...

  6. mysql主从之slave-skip-errors和sql_slave_skip_counter

    一般来说,为了保险起见,在主从库维护中,有时候需要跳过某个无法执行的命令,需要在slave处于stop状态下,执行 set global sql_slave_skip_counter=1以跳过命令.但 ...

  7. 兼容当前多浏览器的渐变颜色背景gradient的写法

    经常有一些时候需要使用渐变背景,使用长条图片有点太不高大上了,于是自己写了个小例子,兼容多浏览器就要为每一个浏览器写对应的CSS,太低版本的浏览器只能使用图片做背景. 下面是当前五大浏览器对gradi ...

  8. AlloyRenderingEngine燃烧的进度条

    写在前面 Github: https://github.com/AlloyTeam/AlloyGameEngine HTML 5新增了progress标签,那么再去使用AlloyRenderingEn ...

  9. canvas 制作flappy bird(像素小鸟)全流程

    flappy bird制作全流程: 一.前言 像素小鸟这个简单的游戏于2014年在网络上爆红,游戏上线一段时间内appleStore上的下载量一度达到5000万次,风靡一时, 近年来移动web的普及为 ...

  10. iOS获取app图标和启动图片名字(AppIcon and LaunchImage's name)

    在某种场景下,可能我们需要获取app的图标名称和启动图片的名称.比如说app在前台时,收到了远程通知但是通知栏是不会有通知提醒的,这时我想做个模拟通知提示,需要用到icon名称:再比如在加载某个控制器 ...