mysql5.7索引合并:交集、并集,EXPLAIN例子

索引合并/index merge。此文的所有SQL例子都基于以下表结构讲解:

CREATE TABLE `t_user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'primary key',
  `username` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT 'user name',
  `age` int(4) NOT NULL DEFAULT 20 COMMENT 'user age',
  `birthday_date_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'user birthday',
  `address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
  `remark` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT 'remark something',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'create time',
  `version` int(4) NOT NULL DEFAULT 0 COMMENT 'update version',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `idx_name`(`username`) USING BTREE,
  INDEX `idx_age_remark`(`age`, `remark`) USING BTREE,
  INDEX `idx_create_time`(`create_time`) USING BTREE,
  INDEX `idx_address`(`address`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 10003 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = DYNAMIC;

一、Intersection合并:交集合并

EXPLAIN SELECT * FROM t_user WHERE address = 'shanghaishi' and create_time = '2021-06-22 09:58:07';    同时使用了address和create_time两个索引列,先从这两个索引列的二级索引树上找到值,然后把相应的ID合并起来回表,这样比一般情况下只使用单个二级索引再回表再用Using Where要快。而即使肉眼可见可能使用交集合并,mysql也不一定会用,因为还涉及查询成本计算,所以要判断一定会走交集合并的,会有这几种情况:

1)等值匹配:

注意:在上面这个等值匹配的例子中,两个二级索引都不是联合索引,如果任何其中一个二级索引是联合索引比如age列,是二级索引范围匹配,那么还是不会走并集索引,因为没有用到remark这个联合索引的第二个,也就是可能范围会太大。

2)主键列范围匹配

因为主键列索引树按照主键排序了,所以范围匹配是有序的。有序的主键 ROR

二、Union合并:并集合并

二级索引列等值查询。这个查询查出来的ID自然而然是个有序的,直接合并就完了。

三、Sort-Union合并:并集合并后再排序

这个sql并不能使主键有序查询,但这里确实用到了两个二级索引,那么从各自的二级索引树里拿到ID后,把ID排好序,做一次排序,再来合并。所以比Union多了一次ID排序的过程。

四、解决方案:联合索引代替Intersection索引合并

这里的解决方案,可以是两个列做一个联合索引即可。

end. 

 

posted on 2021-07-03 19:17  梦幻朵颜  阅读(571)  评论(0编辑  收藏  举报