在学习索引的时候,经常会看到回表、覆盖索引、索引下推、页分裂等等概念,本篇就常见概念进行介绍和总结,但愿能帮助你们快速掌握这些“高大上”的概念。mysql
索引基于B+树,要想更好地理解这些概念建议先了解谈谈MySQL索引底层实现之数据结构和数据结构之B+树算法
根据叶子节点的内容, 索引类型分为主键索引和非主键索引。(mysql索引的数据结构是B+树,对这方面知识看不懂的能够参考)sql
基于主键索引和普通索引的查询有什么区别?性能优化
普通索引查询方式,则须要先搜索索引树,获得主键值,再到主键索引树按主键值搜索一次,这个过程称为回表。数据结构
也就是说,基于非主键索引的查询须要多扫描一棵索引树。 所以, 咱们在应用中应该尽可能使用主键查询。函数
什么是页分裂?性能
若是R5所在的数据页已经满了, 根据B+树的算法, 这时候须要申请一个新的数据页,而后挪动部分数据过去。这个过程称为页分裂。 固然有分裂就有合并。当相邻两个页因为删除了数据,利用率很低以后, 会将数据页作合并。 合并的过程, 能够认为是分裂过程的逆过程mysql索引
页分裂的坏处学习
除了性能外, 页分裂操做还影响数据页的利用率。本来放在一个页的数据, 如今分到两个页中,总体空间利用率下降大约50%。优化
如何避免页分裂?
使用自增主键。每次插入一条新记录, 都是追加操做,都不涉及到挪动其余记录,也不会触发叶子节点的分裂。
自增主键的其余好处
因为每一个非主键索引的叶子节点上都是主键的值。,若是用身份证号作主键, 那么每一个二级索引的叶子节点占用约20个字节, 而若是用整型作主键, 则只要4个字节, 若是是长整型(bigint)则是8个字节。显然, 主键长度越小, 普通索引的叶子节点就越小, 普通索引占用的空间也就越小。
有没有什么场景适合用业务字段直接作主键的呢?
好比,有些业务的场景需求是这样的:
因为没有其余索引, 因此也就不用考虑其余索引的叶子节点大小的问题。这时候咱们就要优先考虑上一段提到的“尽可能使用主键查询”原则, 直接将这个索引设置为主键,能够避免每次查询须要搜索两棵树。
非汇集索引的B+树节点存储的是索引列和主键,假如想要拿到完整数据的话还得根据主键去主键索引树回表,这样性能很差,若是咱们要查询获得的数据就是索引列和主键中的数据,就不要回表。这样只须要在一棵索引树上就能获取SQL所需的全部列数据无需回表的索引称为覆盖索引
因为覆盖索引能够减小树的搜索次数, 显著提高查询性能, 因此使用覆盖索引是一个经常使用的性能优化手段。
B+树这种索引结构, 能够利用索引的“最左前缀”来定位记录。
索引树排序规则:在对联合索引创建索引树时,会按照索引字段的顺序依次排序。以(name,age,address)这个联合索引为例,首先按照name排序完,在name排序值相同时继续按照age排序。
最左匹配:在mysql创建联合索引时还会遵循最左前缀匹配的原则,即最左优先,在检索数据时从联合索引的最左边开始匹配(左边的匹配不上,后面也不会再去匹配了)。同时,索引只能用于查找key是否存在(相等),遇到范围查询 (>、<、between、like
左匹配)等就不能进一步匹配了,后续退化为线性查找。所以,列的排列顺序决定了可命中索引的列数
在创建联合索引的时候, 如何安排索引内的字段顺序?
对字符串的前几个字符(具体是几个字符在创建索引时指定)创建索引,这样创建起来的索引占用空间更小
对字符串创建普通索引和前缀索引的语句以下:
# 普通字符串索引 alter table SUser add index index1(email); # 前缀索引,索引长度为6 alter table SUser add index index2(email(6));
前缀索引的优点和损失
优点:占用的空间会更小
损失:会增长额外的记录扫描次数
使用前缀索引,定义好长度, 就能够作到既节省空间,又不用额外增长太多的查询成本。
当要给字符串建立前缀索引时如何肯定应该使用多长的前缀?
前缀索引确定会损失区分度,咱们须要提早预设一个能够接受的损失比列,使用count计算出多种长度的损失比例,选择低于损失比例的最短长度。
第一步:计算算出这个列上有多少个不一样的值:
select count(distinct email) as L from SUser
第二步:计算不一样长度去重后有多少数据:
select count(distinct left(email,4)) as L4, count(distinct left(email,5)) as L5, count(distinct left(email,6)) as L6, count(distinct left(email,7)) as L7, from SUser;
第三步:选择合适的长度
在返回的L4~L7中,找出不小于 L * 95%的值,假设这里L六、L7都知足,你就能够选择前缀长度为6。
前缀索引对覆盖索引的影响
使用前缀索引就不能使用覆盖索引对查询性能进行优化了。由于索引只包含了字符串的部分数据。
遇到前缀的区分度不够好的状况时,咱们要怎么办?
上一段咱们说到知足最左前缀原则的时候,最左前缀能够用于在索引中定位记录。 这时,你可能要问,那些不符合最左前缀的部分, 会怎么样呢?
mysql> select * from tuser where name like '张%' and age=10 and ismale=1;
咱们仍是以市民表的联合索引(name, age) 为例。 若是如今有一个需求: 检索出表中“名字第一个字是张, 并且年龄是10岁的全部男孩”。 那么, SQL语句是这么写的:
你已经知道了前缀索引规则, 因此这个语句在搜索索引树的时候, 只能用 “张”, 找到第一个知足条件的记录ID3。 固然, 这还不错, 总比全表扫描要好。而后呢?固然是判断其余条件是否知足。
在MySQL 5.6以前, 只能从ID3开始一个个回表。 到主键索引上找出数据行, 再对比字段值。
而MySQL 5.6 引入的索引下推优化(indexcondition pushdown), 能够在索引遍历过程当中, 对索引中包含的字段(age)先作判断, 直接过滤掉不知足条件的记录, 减小回表次数。
本文记录比较零散,若是有模棱两可或者不对的地方欢迎你们指正。