文章目录

  • 前言
  • 常见的索引类型
  • 聚簇索引/非聚簇索引
  • 覆盖索引
  • 前缀索引
  • 索引下推

前言

索引的出现是为了提高数据查询效率,像书的目录一样。对于数据库的表而言,索引其实就是“目录”。

关于MySQL的系列文章,请跳转至 MySQL专栏

常见的索引类型

  • 哈希表
  • 有序数组
  • 搜索树

哈希表

哈希表是以 KV 形式存储数据的结构,只要输入key,就可以找到对应的 value,思路很简单,就是放到数组中,根据 hash 算法计算出key在数组中确定的索引位置,把 value 存储在这个索引位置。当两个不同的 key 经过 hash 算法计算出的 索引位置相同时,就出现了哈希碰撞,这时用一个链表解决。查询的时候,根据 hash 算法计算出 value 所在数组的索引位置,然后按链表顺序遍历,直到找到 key 对应的 value

哈希表中存储数据不是按照 key 的顺序递增排序的,如果需要做范围查询的话,使用哈希结构就不得不全部扫描一遍了。

所以,哈希结构适用于等值查询的场景,比如 NoSQL

有序数组

有序数组不管是等值查询还是范围查询场景中性能都很好。等值查询时,可以根据二分查找法定位元素,时间复杂度是 O(logn);如果是范围查询时,可以先用二分法查找到范围的下限,再向右遍历,知道查到第一个不符合范围的值,退出循环。

如果只看查询效率,有序数组是最好的数据结构了。但是,如果要新增数据,往其中数组中插入一个元素,要挪动后面所有记录,成本太高。所以,有序数组只适用于静态存储引擎,比如不会再修改,只需要查询的数据。

搜索树

二叉搜索树的节点是有序的,左节点都小于根节点,右节点都大于根节点。二叉搜索树如果出现极端的情况,性能极差,所以,平衡二叉树的查询性能更好。但是平衡二叉树的结构,每次读数据块都需要从磁盘加载到内存,为了减少 I/O 操作,要尽可能的少读磁盘,平衡多叉树可以解决这个问题,每个节点有多个子节点,这样树的高度相较于二叉树来说,低的多,查询过程中就会访问较少的数据块,从而提高查找效率。


聚簇索引/非聚簇索引

众所周知,InnoDB采用的是B+Tree这种数据结构,B+Tree 也是一种平衡多叉树。InnoDB 表中的数据都是根据主键顺序以索引的形式存放的,每一个索引在 InnoDB 中对应一棵 B+Tree ,索引类型又分为:主键索引和非主键索引。

主键索引的叶子节点存的是整行数据,在 InnoDB 中,主键索引也被称为聚簇索引。

非主键索引的叶子节点存的是主键的值,在 InnoDB 中,非主键索引也被称为二级索引。

基于主键索引和普通索引的查询有什么区别?

如果 SQL 中的 where 条件是主键,则只需要搜索主键索引的B+Tree即可查询该数据;

如果 SQL 中的 where 条件是普通索引,则先搜索普通索引的 B+Tree,得到主键的值,再根据主键的值搜索主键索引的B+Tree查询到需要的数据,这个过程称为回表。

所以,基于非主键索引的查询需要多扫描一棵树,因此,在应用中应该尽量使用主键查询。

为什么说主键的长度要尽量小并且是自增的?

B+Tree 在插入新节点时,如果插入的节点值比当前树中的值都大时,则直接插入即可。而如果插入的节点值在当前树中的值处于中间位置,就需要挪动部分数据,空出位置再插入新数据。而如果要插入数据页满了,根据B+Tree 的算法,需要申请一个新的数据页,再挪动部分数据,这个过程叫做页分裂。有分裂的情况就有合并的情况,当从树中删除一个节点时,剩余的数据在数据页中的利用率很低的时候,会将数据页做合并操作,就是分裂的逆过程。

而之所以要求主键自增是因为,如果每次要插入的节点都比当前树中最大值还大,都是追加操作,则不会触发叶子节点的分裂。

要求主键的长度要尽量短,上面我们说过,每个非聚集索引的B+Tree中存的是元素对应的主键,如果主键越长,占用的内存空间越大;而主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间就越小。

覆盖索引

这条 SQL中 select * from T where k between 3 and 5,id 为主键,k 为普通索引。这条SQL的执行流程是什么样的?

  • k是普通索引,遍历k索引树,找到范围的下限3,取得对应的主键,再到主键索引树中查询主键对应的数据行。
  • 再回到k索引树取下一个值,判断是不是在要查询数据的范围内,如果在,再取到对应的主键,再去主键索引树查询到对应的数据行。
  • 直到找到超出查找的数据范围时,查找结束

上述过程中不可避免的出现了回表操作,因为数据行只有主键索引上存在,只能去遍历主键索引树。

如果执行的 SQL 是:select id from T where k between 3 and 5

  • 只需要查到遍历 k 索引树从叶子节点查到 id 的值,直到找到超出查找的数据范围时,查找结束,不需要回表操作

在这个查询中,索引 k 已经覆盖了查询需求,称为覆盖索引。由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。

前缀索引

有一种索引是联合索引,指的是由多个字段组成的索引,也称复合索引。

如果有一个联合索引(name,age),下面通过实例说明最左前缀原则。

根据上面的联合索引,现在有如下需求:

  1. 要求查出所有名字是“张三”的人
  2. 要求查出所有姓“李”的人
  3. 要求查出所有名字中最后一个字是 “山”的人
  4. 要求查出所有年龄为 18 的人

1 的SQL条件写成:where name = "张三",可以使用(name,age)联合索引查询,也就是从索引的最左侧开始,这个最左前缀可以是联合索引的最左N个字段。

2 的SQL条件:where name = "李%",这时,也可以使用联合索引。

3 的SQL条件:where name = "%山",这时,不可以使用联合索引,会导致索引失效

4 的SQL条件:where age = 18,这时,不可以使用联合索引,因为查询条件不是联合索引的最左N个字段。

综上所述,在建立联合索引时,要安排好索引的字段顺序。否则,很有可能导致索引失效。对于(name,age)联合索引,符合条件的查询条件是:

  • where name = …
  • where name = … and age = …
  • where name = … and age in (… , …)
  • order by name,age
  • where name = … order by age

还有很多情况会导致索引失效,看看都有哪些情况:

  • or 前后查询条件不都是索引子段(or 前后查询字段都是索引时会生效)
  • 未遵循最左N个字段
  • 模糊查询 like 以 % 开头
  • 需要类型转换
  • where 中索引列有计算
  • where 中索引列用到了函数
  • 索引字段上使用 not , <> , != (不等于操作符会触发全表扫描)
  • 当全表扫描速度比索引速度快时

索引下推

上面讲解了最左前缀原则,如果联合索引中不符合最左前缀原则的部分,会怎么样呢?

我们还是以联合索引(name, age)为例,要求检索出表中 “名字第一个字是张,而且年龄是10岁的所有男孩”。那么,SQL语句是这么写的:

select * from tuser where name like '张%' and age=10 and ismale=1;

这个语句在搜索索引树的时候可以使用联合索引,先覆盖了 name 索引,找到第一个name字段满足"张%"的记录后,开始回表查询数据行,再从联合索引树上找下一个字段值做对比。

在MySQL 5.6之前,只能从第一个满足name条件的值开始一个个回表。到主键索引上找出数据行,再对比字段值。

而MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。

如下图,分别是 MySQL 5.6 前 和 5.6 后的执行流程图。



第一个图中,也就是无索引下推的流程图中,这个过程InnoDB并不会去看age的值,只是按顺序把“name第一个字是’张’”的记录一条条取出来回表。因此,需要回表4次。

使用了索引下推的流程图中,InnoDB在(name,age)索引内部就判断了age是否等于10,对于不等于10的记录,直接判断并跳过。在我们的这个例子中,只需要对ID4、ID5这两条记录回表取数据判断,就只需要回表2次。

简单易懂的MySQL覆盖索引、前缀索引、索引下推相关推荐

  1. 【MongoDB】索引之复合索引

    本章内容: 创建复合索引 排序 前缀 索引交集 其他注意事项 MongoDB支持复合索引(compound indexes),一个复合索引包含对集合文档中多个字段[1]的引用.下图说明了两个字段上的复 ...

  2. MySQL 覆盖索引、最左前缀原则、索引下推

    1.覆盖索引 1.1 概念 索引是高效找到行的一个方法,当能通过检索索引就可以读取想要的数据,那就不需要再到数据表中读取行了.如果一个索引包含了(或覆盖了)满足查询语句中字段与条件的数据就叫做覆盖索引 ...

  3. 覆盖索引最左前缀原则索引下推

    覆盖索引 如果执行的语句是 select ID from T where k between 3 and 5,这时只需要查 ID 的值,而 ID 的值已经在 k 索引树上了,因此可以直接提供查询结果, ...

  4. mysql索引篇之覆盖索引、联合索引、索引下推

    覆盖索引 在之前<mysql索引初识>这篇文章中提到过,mysql的innodb引擎通过搜索树方式实现索引,索引类型分为主键索引和二级索引(非主键索引),主键索引树中,叶子结点保存着主键即 ...

  5. 覆盖索引与联合索引_浅析MySQL的索引覆盖和索引下推

    写在前面 在MySQL数据库中,索引对查询的速度有着至关重要的影响,理解索引也是进行数据库性能调优的起点,索引就是为了提高数据查询的效率.今天我们来聊聊在MySQL索引优化中两种常见的方式,索引覆盖和 ...

  6. mysql索引创建规则、联合与一般索引、执行计划、索引选择,索引重建与下推

    数据库索引怎么建,什么时候用到 索引优缺点:为主键外建where子句建立索引可以加速数据库查询,但是索引占用内存,同时update和insert的时候需要同步修改;索引的实现通常使用其变种B+树. 建 ...

  7. MySQL-索引优化篇(1)_安装演示库 [前缀索引、联合索引、覆盖索引] explain参数

    文章目录 生猛干货 官方文档 安装演示数据库sakila 索引优化策略 索引列上不能使用表达式或者函数 前缀索引和索引列的选择性 前缀索引的创建 索引列的选择性 前缀索引的优缺点 联合索引 如何选择索 ...

  8. sql优化之:数据库索引创建原则,or/in/union与索引优化,聚集索引/非聚集索引/联合索引/索引覆盖,MySQL冗余数据的三种方案,MySQL双主一致性架构优化(来源:架构师之路)

    一.一些常见的SQL实践 (1)负向条件查询不能使用索引 select * from order where status!=0 and stauts!=1 not in/not exists都不是好 ...

  9. Mysql:好好的索引,为什么要下推?

    作者|莱乌 前段时间有读者提议讲讲索引下推,这期就把这事儿安排上.多余的前言就不赘述了,我们直接开始. 列位坐好! - 思维导图 - 回表操作 对于数据库来说,只要涉及到索引,必然绕不过去回表操作.当 ...

最新文章

  1. 【c语言】蓝桥杯算法训练 P0505
  2. 一张照片生成积木的你!5个在校生2个月做的AI项目,李开复看了赞不绝口
  3. 如何在linux程序中捕获异常信号
  4. 100~200之间的素数(及其四个优化方案)
  5. 使用Lucid Virtu在有独立显卡的情况下使用Intel硬件加速H.264编码
  6. return view前端怎么获取_Web 前端路由原理解析和功能实现
  7. js字符串转换为json对象JSON.parse()及将json对象转为json字符串JSON.stringify()
  8. Linux系统的账号管理
  9. setInterval 和 setTimeout
  10. Golang中对new和make的理解
  11. ThoughtWorks笔试题大致解题思路总结
  12. python实现千牛客服自动回复语_千牛客服自动回复话术
  13. Could not get a resource from the pool 问题解决
  14. iPhone音频开发之:转换和录音(第二部分)
  15. LocalSend 电脑和手机互传软件教程解答手机端无法搜索到电脑的解决方案
  16. linux脚本第一行是什么,完全搞懂shell脚本第一行:#!/bin/bash的含义
  17. gRPC详细入门教程,Golang/Python/PHP多语言讲解
  18. 用jQuery--实现todolist待办事项清单
  19. 菜鸟慢慢爬行-----web(5)
  20. 如何进入训练模式_健身计划非常重要,对于健身小白,新手期和成长期该如何制定?...

热门文章

  1. 玩转Linux与运维岗(15)
  2. cad中英文翻译插件使用
  3. 为了完善Apple Music,苹果又花了4亿美元收购一家公司
  4. Python练习_数据类型_day5
  5. python中sort函数源代码_Python中sort和sorted函数代码解析
  6. 关于PHP开发编码规范
  7. 下列python保留字中、用于异常处理_下列Python保留字中,用于异常处理结构中用来捕获特定类型异常的是...
  8. 教程篇:《基础模块6》金蝶K3WISE15.0-账套用户引入引出;怎样把用户及权限引入到另一个账套
  9. docker+Locust+Prometheus+Grafana实现性能监控平台
  10. 【黑马程序员西安中心】不忘初心,砥砺前行