记一次MySql单列索引和联合索引的使用区别

状况是这样,有一张表,创建了一个组合索引,好比:userId,userType,orgId这三个字段组合,顺序也是这样的,而后写sql的时候这样写的:mysql

 select * from user where userType=0 and userId=1;

 同事说这样写SQL的效率会有影响,创建联合索引的时候字段是什么顺序就要按照顺序来,因此要把后面的where条件改成 userId=1 and userType=0才能够,之前还真没有注意过,此次本身亲自试验了一下。sql

创建两张表,其实表结构同样,只不过表名和索引类型不同app

CREATE TABLE `gift` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键,自增',
  `name` varchar(50) DEFAULT NULL COMMENT '道具名称',
  `description` varchar(300) DEFAULT NULL COMMENT '道具功能简介',
  `status` tinyint(1) DEFAULT NULL COMMENT '道具状态,1:启用中,0:',
  `scene_type` int(11) DEFAULT NULL COMMENT '场景类型,0:直播场景,1:回放场景',
  `price` float DEFAULT NULL COMMENT '价格',
  `integration` float DEFAULT NULL COMMENT '道具积分',
  `charge_status` int(11) DEFAULT NULL COMMENT '收费状态(0:免费,1:收费,2:折扣)',
  `rank` int(11) DEFAULT NULL COMMENT '排序,好比有新道具,须要优先进行推荐',
  `app_id` int(11) DEFAULT NULL COMMENT '应用的标识',
  `create_time` datetime DEFAULT NULL COMMENT '建立时间',
  `create_user` int(11) DEFAULT NULL COMMENT '建立人ID',
  `data` varchar(1000) DEFAULT NULL COMMENT '预留字段,用来存放logo,效果图等信息,JSON串形式',
  PRIMARY KEY (`id`),
  KEY `idx` (`name`,`status`,`scene_type`,`app_id`)
) ENGINE=InnoDB AUTO_INCREMENT=786663 DEFAULT CHARSET=utf8;

 

第一张表gift和索引为联合索引,如图:mysql索引

第二张表gift2为单列索引,如图:测试

 

下面开始进行测试:优化

相同的SQL分别查询两张表,使用EXPLAIN解析一下SQLspa

EXPLAIN select * from gift where `name`='道具' and scene_type=1;
EXPLAIN select * from gift2 where `name`='道具' and scene_type=1;

     显示的结果为两条SQL都会使用到索引,这我就不上图了。code

而后只查询其中的某列,可是这个列已经建立索引排序

EXPLAIN select `name`,`status` from gift where `name`='道具' and scene_type=1;
EXPLAIN select `name`,`status` from gift2 where `name`='道具' and scene_type=1;

    显示的结果为两条SQL也都使用了索引。索引

继续查询没有建立索引的列,这里rank字段并无建立索引

EXPLAIN select `name`,`status`,rank from gift where `name`='道具' and scene_type=1;
EXPLAIN select `name`,`status`,rank from gift2 where `name`='道具' and scene_type=1;

     显示的结果为两条SQL也都使用了索引。

接下来把SQL调整一下,name字段都创建了索引,下面把where条件里的name条件去掉

EXPLAIN select `name`,`status` from gift where scene_type=1;
EXPLAIN select `name`,`status` from gift2 where scene_type=1;

     显示的结果为两条SQL也都使用了索引。

仍是上面这条SQL,把rank列再加上去,再查看下效果

EXPLAIN select `name`,`status`,rank from gift where scene_type=1;
EXPLAIN select `name`,`status`,rank from gift2 where scene_type=1;

    这个时候比较奇怪的事情就出来,第一条SQL根本没有用到索引,第二条SQL还和之前同样,一样使用到了索引。

其实在联合索引上会有一个mysql索引最左匹配原则,可是若是联合索引的第一个列不在where条件语句中,而且所查询的列其中有的是没有创建索引的,那么这个联合索引就是无效的,具体为何会这样我也尚未整明白(囧),不过之后再写SQL也会注意一下这方面的问题,并且公司DBA也建议若是使用联合索引,那么where条件也要尽可能根据联合索引的顺序来,若是不按照顺序来,索引也一样会用到,可是在执行前,SQL优化器也会将条件调整为联合索引的顺序,既然能够直接避免这种状况,就不必再让SQL优化器去处理,毕竟处理也是有开销的。

相关文章
相关标签/搜索