前言
索引匹配遵循最左匹配原则,那是为什么呢?欲知详情,请看下文分解。
概述
MySQL存储引擎InnoDB 索引都是B-tree数据结构。空间索引使用 R-trees。
InnoDB架构图:
B-Tree与B+Tree区别
Innodb 存储引擎的 B-Tree 索引实际使用的存储结构实际上是 B+Tree。
B+Tree在 B-Tree 数据结构的基础上做了改造,在每一个Leaf Nod 上面出了存放索引键的相关信息之外,还存储了指向与该 Leaf Node 相邻的后一个 LeafNode 的指针信息(增加了顺序访问指针),这主要是为了加快检索多个相邻 Leaf Node 的效率考虑。
联合索引树
创建一个(name,age,address) 的联合索引,索引树如下: 上图中name的值是有顺序的按首字母的 a,b,c 排,而age和address的值是没有顺序的。
所以age = 38这种查询条件没有办法利用索引,因为联合索引首先是按name排序的,age是无序的。
最左匹配
最左匹配原则:最左优先,以最左边的为起点任何连续的索引都能匹配上。同时遇到范围查询(>、<、between、like)就会停止匹配。
假如建立联合索引(a,b,c)
全值匹配查询
全值匹配指的是和索引中的所有列进行匹配。
select * from table_name where a = '1' and b = '2' and c = '3'
select * from table_name where b = '2' and a = '1' and c = '3'
select * from table_name where c = '3' and b = '2' and a = '1'
where子句几个搜索条件顺序调换不影响查询结果,因为Mysql中有查询优化器,会自动优化查询顺序
匹配最左前缀
只使用索引的第一列。
select * from table_name where a = '1'
select * from table_name where b = '2'
select * from table_name where c = '3'
select * from table_name where b = '1' and c = '3'
这些没有从最左边开始,最后查询没有用到索引,用的是全表扫描
select * from table_name where a = '1' and c = '3'
如果不连续时,只用到了a列的索引,b列和c列都没有用到
匹配列前缀
匹配某一列值得开头部分。
select * from table_name where a like 'As%';
select * from table_name where a like '%As'
select * from table_name where a like '%As%'
匹配范围值
select * from table_name where a > 1 and a < 3
可以对最左边的列进行范围查询
select * from table_name where a > 1 and a < 3 and b > 1;
多个列同时进行范围查找时,只有对索引最左边的那个列进行范围查找才用到B+树索引,也就是只有a用到索引,在1<a<3的范围内b是无序的,不能用索引,找到1<a<3的记录后,只能根据条件 b > 1继续逐条过滤。
精确匹配某一列并范围匹配另外一列
如果左边的列是精确查找的,右边的列可以进行范围查找
select * from table_name where a = 1 and b > 3;
a=1的情况下b是有序的,进行范围查找走的是联合索引。
排序
一般情况下,我们只能把记录加载到内存中,再用一些排序算法,比如快速排序,归并排序等在内存中对这些记录进行排序,有时候查询的结果集太大不能在内存中进行排序的话,还可能暂时借助磁盘空间存放中间结果,排序操作完成后再把排好序的结果返回客户端。 MySQL中把这种再内存中或磁盘上进行排序的方式统称为文件排序。
文件排序非常慢,但如果order子句用到了索引列,就有可能省去文件排序的步骤: 因为b+树索引本身就是按照上述规则排序的,所以可以直接从索引中提取数据,然后进行回表操作取出该索引中不包含的列就好了。
order by的子句后面的顺序也必须按照索引列的顺序给出,比如
select * from table_name order by a,b,c limit 10;
如下颠倒顺序的没有用到索引:
select * from table_name order by b,c,a limit 10;
如下用到部分索引:
select * from table_name order by a limit 10;
select * from table_name order by a,b limit 10;
如下联合索引左边列为常量,后边的列排序可以用到索引:
select * from table_name where a =1 order by b,c limit 10;
点赞 收藏 关注
|