目录
索引介绍
索引的数据结构
哈希表
有序数组
搜索树(二叉搜索树、N叉搜索树、B+树)
索引类型
主键索引和非主键索引
主键索引数据来源
索引叶子节点存储内容
主键的选择
联合索引
最左前缀原则
索引下推
范围查询会阻断后续列匹配
覆盖索引
回表
避免回表
前缀索引
前缀索引的局限性
总结
按数据结构分类
按物理存储分类
按字段特性分类
按字段个数分类
索引的出现其实就是为了提⾼数据查询的效率,对于数据库的表来说,索引就是它的目录
常见的三种实现索引的数据结构: 哈希表、有序数组、搜索树
现在最常用的索引的数据结构是N叉搜索树中的B+树
哈希表实现原理: 以键值对方式存储,输入key 经过哈希函数转化,找到数组的位置,相同位置使用链表进行存储,因为不是有序,所以做区间查询很慢
有序数组实现原理: 以键值对方式存储,查询数据通过二分法快速得到,有序,支持区间查询,但更新数据需要挪动的数据太多,成本太高
二叉搜索树实现原理:⽗节点左⼦树所有结点的值⼩于⽗节点的值,右⼦树所有结点的值⼤于⽗节 点的值,搜索快速,而且保证有序,容易插入和删除,是最理想的数据结构
二叉搜索树的优化
因为二叉搜索树构建起来层级太深,在获取索引读磁盘的时候需要读很多磁盘数据块,浪费时间,我们必须要在查询过程中尽可能少的读取磁盘的数据块,我们需要层级浅的搜索树,由此可得出,N叉搜索树更适合当作索引的数据结构
在多种N叉搜索树中,我们选择B+树作为索引的数据结构,优势是B+树只有叶子节点存储数据,非叶子节点起索引作用,B+树单个节点数据量小,在相同的磁盘IO次数下,可以查到更多的节点,B+树采用的是双链表连接,适合MySQL中常见的基于范围查找
这部分我会先单独介绍比较难理解的索引类型,最后会对索引类型做一个总结归纳
在InnoDB中,表都是根据主键顺序以索引的形式存放的,表数据存储到主键索引中,InnoDB使⽤了B+树索引模型,所以数据都是存储在B+树中的
每⼀个索引在InnoDB⾥⾯对应⼀棵B+树
主键索引存储表数据,所以它的叶子节点是整行的数据
非主键索引只是起到了目录的作用,所以它的叶子节点存储的是主键值和索引列
B+树为了维护索引有序性,在插⼊新值的时候需要做必要的维护,如果我们的主键不是有序的,大幅度挪数据,可能会导致一个表跨多个数据页,形成页分裂,而且非主键索引的叶子节点都存储的是主键,所以综上所述,我们要保证主键有序并且主键长度尽量的小,所以一般情况来说,主键自增就是性能最优的选择
联合索引就是有多个索引字段的索引
联合索引的数据是按照联合索引字段的先后数据进行排序的
在联合索引中前面的字段是一个确定值,后面的字段才在这个条件基础上有序
联合索引中,在索引回表之前,会先对索引中包含的字段先做判断,直接过滤掉不满⾜条件的记录,减少回表次数
范围查询(如 >
、LIKE
、BETWEEN
)会导致后续的索引“有序性”被破坏,后续列无法继续按索引顺序匹配。当然,第一个范围查询还是生效的,后续破坏有序性了,就不会再往下匹配了
举个例子
-- 索引 (A, B, C)
SELECT * FROM table WHERE A = 1 AND B >= 10 AND C = 20;
此时索引A、B字段索引生效,B是范围查询,所以阻断了后续列的匹配,C字段失效
本质就是使用非主键索引查询数据,先查非主键索引中的主键值,拿着主键值查询主键索引的整行数据
本质就是第一次查询非主键索引的时候,需要查询的字段索引列里面都有,所以只需要查询非主键索引拿到主键和索引列就得到想要的结果了
即建立联合索引的索引字段要覆盖查询的字段,此时就避免回表了,这种联合索引又称为覆盖索引
但是索引字段维护会有代价的,所以考虑建立覆盖索引的时候需要综合考虑是否值得
1、表中只能由一个索引,这样就排除了非主键索引叶子节点大小的考虑
2、而且这个索引必须是唯一索引,此时就只能使用业务字段当作主键了
它通过对字段值的前N个字符(或字节)建立索引,这种设计在节省存储空间和提高查询效率之间取得了平衡,尤其适用于长字符串字段
前缀索引只包含部分字段值,无法直接用于ORDER BY
或GROUP BY
完整字段
无法用于覆盖索引,如果查询需要完整字段值,仍需回表
B+树索引、有序数组索引、Hash表索引
B+树索引常见的存储引擎都支持
有序数组索引常见的引擎都不支持
Hash表索引Memory存储引擎支持
主键索引和非主键索引
主键索引: 在创建表时一起创建的,一张表最多只有一个主键索引
唯一索引: 一张表可以有多个唯一索引,值必须唯一,允许空值
普通索引: 对字段无要求
前缀索引: 指对字符类型字段的前几个字符建立的索引,减少索引占用存储空间
单列索引: 单例建立索引
联合索引: 多列建立索引