mysql-5.回表、覆盖索引、最左匹配原则

回表

通过上一章的介绍,我们知道索引可以分为主键索引和非主键索引。非主键索引的叶子节点存储的是主键索引的值。
我们在通过非主键索引查询时候,需要先在非主键索引树找到主键值,然后再到主键索引树根据主键值去查询出整行数据,这个过程中,回到主键索引树搜索的过程,我们称为回表

覆盖索引
#创建一张表
mysql> create table T (
ID int primary key,
k int NOT NULL DEFAULT 0, 
s varchar(16) NOT NULL DEFAULT '',
index k(k))
engine=InnoDB;

#插入的数据
insert into T values(100,1, 'aa'),(200,2,'bb'),(300,3,'cc'),(500,5,'ee'),(600,6,'ff'),(700,7,'gg');

索引树的结构为:
在这里插入图片描述
对于上面的表我们执行下面这条查询语句:select ID from T where k between 3 and 5
这个时候,输出列只需要查询ID,而索引树k上面已经有ID信息了,因此可以直接返回结果,不用再去ID主键索引树上搜索了,就避免了回表
也就是说,在这个查询里面,索引 k 已经“覆盖了”我们的查询需求,我们称为覆盖索引

tips:由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。
例如: 我们公司的内部通信软件,经常会用员工工号查询员工姓名,这样一个高频搜索需求,那么我们就可以建立一个(工号,姓名)的联合索引,通过合理使用联合索引,来实现覆盖索引,提高查询效率。
当然,索引字段的维护总是有代价的。因此,在建立冗余索引来支持覆盖索引时就需要权衡考虑了。

最左匹配原则

我们建立一个联合索引 idx_abc(a,b,c)

查询条件索引是否生效
where a=#{a} and b=#{b} and c=#{c}idx_abc生效
where c=#{c} and b=#{b} and a=#{a}idx_abc生效(特殊性情况,优化器会处理,最后又会变成abc顺序)
where a=#{a} and b=#{b}idx_abc生效
where a=#{a}idx_abc生效
where a=#{a} and c=#{c}idx_abc生效
where b=#{b}idx_abc不生效
where c=#{c}idx_abc不生效
where b=#{b} and c=#{c}idx_abc不生效

可以看到,不只是索引的全部定义,只要满足最左前缀,就可以利用索引来加速检索。这个最左前缀可以是联合索引的最左 N 个字段,也可以是字符串索引的最左 M 个字符。

  1. 查询条件的第一个一定要和联合索引顺序匹配上,否则索引失效。这个时候,如果我们字段c才是高频搜索条件呢,我们又不能不建索引,所以只能新建一个idx_c(c)的索引。但是我们是否可以考虑,调整索引顺序,将idx_abc(a,b,c)改为idx_abc(c,b,a)呢?这样我们就不用单独去建立一个idx_c索引了。当然这个是否可以这么修改还是要看实际业务场景。
  • 所以就有了第一原则:如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的。
  1. 如果对于联合索引idx_ab(a,b),既有联合的查询,又有基于a ,b各自的查询。那我们是建立(a,b)(b)这两个索引还是建立(b,a)(a)这两个索引呢?那么需要考虑单独的这个索引怎么样可以占用更少的磁盘空间
  • 这时候我们需要从节省空间角度出发了,单独建立的索引谁站的空间更小。

给大家贴个表结构,大家可以亲自动手试下

CREATE TABLE `t_test` (
  `id` int(11) DEFAULT NULL,
  `a` varchar(255) DEFAULT NULL,
  `b` varchar(255) DEFAULT NULL,
  `c` varchar(255) DEFAULT NULL,
  KEY `idx_abc` (`a`,`b`,`c`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `t_test` (`id`, `a`, `b`, `c`) VALUES ('1', 'a1', 'b1', 'c1');
INSERT INTO `t_test` (`id`, `a`, `b`, `c`) VALUES ('2', 'a2', 'b2', 'c3');

#通过explain来看下索引是否生效
EXPLAIN select * from t_test where a='a1' and b='b1' and c='c1'
EXPLAIN select * from t_test where a='a1' and b='b1'
EXPLAIN select * from t_test where  a='a1'
EXPLAIN select * from t_test where b='b1'
EXPLAIN select * from t_test where c='c1'
EXPLAIN select * from t_test where a='a1' and c='c1'
EXPLAIN select * from t_test where b='b1' and c='c1'
EXPLAIN select * from t_test where c='c1' and b='b1' and a='a1'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值