最近在看MySQL索引的知识,看到组合索引的时候,有一个最左侧原则,我就建了个简单的表验证一下,过程中碰到有些不懂的,在这里求教一下,mysql版本5.7的
CREATE TABLE `testp` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`users_id` int(10) unsigned NOT NULL COMMENT '学生用户ID',
`activity_id` int(11) NOT NULL COMMENT '活动ID',
`phone` varchar(20) NOT NULL COMMENT '手机号码',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_activity_users` (`activity_id`,`users_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='名表';
-- ----------------------------
-- Records of testp
-- ----------------------------
INSERT INTO `testp` VALUES ('1', '272002', '17', '12345678900');
INSERT INTO `testp` VALUES ('2', '290253', '19', '12345678900');
INSERT INTO `testp` VALUES ('3', '177652', '17', '12345678900');
INSERT INTO `testp` VALUES ('4', '36482', '17', '12345678900');
INSERT INTO `testp` VALUES ('5', '36482', '19', '12345678900');
INSERT INTO `testp` VALUES ('6', '290253', '17', '12345678900');
INSERT INTO `testp` VALUES ('7', '272207', '17', '12345678900');
INSERT INTO `testp` VALUES ('8', '272207', '19', '12345678900');
表结构如上,
把activity_id
,users_id
组合一下,navicat上信息如下图:
首先运行第一条sql:
EXPLAIN SELECT * FROM `testp` WHERE activity_id=17 AND users_id=272002;
其结果如下图:
发现key这个列有值,这个是对的
然后我运行如下sql:
EXPLAIN SELECT * FROM `testp` WHERE activity_id=17;
结果是:
发现没有使用到索引,正常情况不是可以使用到索引吗?
之后我又去试了把 activity_id=17改成 activity_id=19:
EXPLAIN SELECT * FROM `testp` WHERE activity_id=19;
结果:
结果显示使用到了索引
也就是说这个和值也有关系???请各位解答下,谢谢!!
之前以为是Unique类型的原因,我把Unique改成Normal结果还是一样的。
mysql优化器认为全表扫描的成本小于使用索引,所以放弃使用索引了。
如果是
的话应该是总是会使用索引的,因为不需要回表
举一个强行走索引可能比直接全表扫描慢的极端例子
对问题中的那张表,假如表中数据如下
对于查询
由于要查询的列包含索引中没有的列
phone
,所以如果走索引idx_activity_users
是需要回表的,即现通过索引获取所有activity_id为19的列的_rowid,然后根据这些_rowid到表中获取所有数据,然而由于索引中activity_id全部是19,没有筛选掉任何数据,相关的开销完全是白费的,还不如直接全表扫描。即使不全是19,只要没能够筛掉足够多的数据,索引再回表的开销还是有可能大于直接扫表的,于是就有了possible_keys有值却没有走索引的情况。
而对于查询
由于索引覆盖了所有查询列(INNODB中所有非主键索引都包含主键列),不需要回表,因此是会使用索引的