搞清楚了MySQL底层的数据结构B+树后,我们应该知道整棵树的非叶子节点存放的都是仅仅是索引,而真正的值都存储在叶子节点中。而我们的MySQL中的索引种类其实又细分为了很多种,本篇带大家一起熟悉MySQL中InnoDB引擎下的那些索引。

聚集索引/聚簇索引/主键索引

InnoDB 中使用了聚集索引,就是将表的主键用来构造一棵 B+树,并且将整张表的行记录数据存放在该 B+树的叶子节点中。也就是所谓的索引即数据,数据即索引。由于聚集索引是利用表的主键构建的,所以每张表只能拥有一个聚集索引。

聚集索引的叶子节点就是数据页。换句话说,数据页上存放的是完整的每行记录。因此聚集索引的一个优点就是:通过过聚集索引能获取完整的整行数据。 另一个优点是:对于主键的排序查找和范围查找速度非常快(不需要回表操作)。

如果我们没有定义主键呢?MySQL 会使用唯一性索引,没有唯一性索引, MySQL 也会创建一个隐含列 RowID 来做主键,然后用这个主键来建立聚集索引。

辅助索引/二级索引/普通索引 /非聚集索引

上边介绍的聚簇索引只能在搜索条件是主键值时才能发挥作用,因为 B+树 中的数据都是按照主键进行排序的,那如果我们想以别的列作为搜索条件怎么 办?我们一般会建立多个索引,这些索引被称为辅助索引/二级索引。

对于辅助索引(Secondary Index,也称二级索引、非聚集索引),叶子节点 并不包含行记录的全部数据。叶子节点除了包含键值以外,每个叶子节点中的索 引行中还包含了一个书签( bookmark)。该书签用来告诉 InnoDB 存储引擎哪里可 以找到与索引相对应的行数据。因此 InnoDB 存储引擎的辅助索引的书签就是相应行数据的聚集索引键。

比如辅助索引 index(node),那么叶子节点中包含的数据就包括了(主键、 note)。

回表

辅助索引的存在并不影响数据在聚集索引中的组织,因此每张表上可以有多个辅助索引。当通过辅助索引来寻找数据时,InnoDB 存储引擎会遍历辅助索引 并通过叶级别的指针获得指向主键索引的主键,然后再通过主键索引(聚集索引) 来找到一个完整的行记录。这个过程也被称为回表。也就是根据辅助索引的值查 询一条完整的用户记录需要使用到 2 棵 B+树----一次辅助索引,一次聚集索引。

为什么需要回表操作

言外之意,我们为什么不在每个索引中都维护卫星数据(整行数据)呢?

内存占用高

相当于每建立一棵 B+树都需要把所有的用户记录再都拷贝一 遍,这就有点太浪费存储空间了。

效率低下

每次对数据的变化要在所有包含数据的索 引中全部都修改一次,性能也非常低下。

优化器未必选择二级索引的原因

很明显,回表的记录越少,性能提升就越高,需要回表的记录越多,使用二 级索引的性能就越低,甚至让某些查询宁愿使用全表扫描也不使用二级索引。

什么时候使用采用二级索引 + 回表的方 式去执行查询呢?这个就是查询优化器做的工作,查询优化器会事先对表中的记 录计算一些统计数据,然后再利用这些统计数据根据查询的条件来计算一下需要 回表的记录数,需要回表的记录数越多,就越倾向于使用全表扫描,反之倾向于 使用二级索引 + 回表的方式。具体怎么算的,我们后面会详细说到。

联合索引/复合索引

底层维护了多个索引,组成了一个索引组

前面我们对索引的描述,隐含了一个条件,那就是构建索引的字段只有一个,但实践工作中构建索引的完全可以是多个字段。所以,将表上的多个列组合起来 进行索引我们称之为联合索引或者复合索引,比如 index(a,b)就是将 a,b 两个 列组合起来构成一个索引。

千万要注意一点,建立联合索引只会建立 1 棵 B+树,多个列分别建立索引会分别以每个列建立 B+树,有几个列就有几个 B+树,比如,index(note)、 index(b),就分别对 note,b 两个列各构建了一个索引。

联合索引的排序规则

index(note,b)在索引构建上,包含了两个意思:

1、先把各个记录按照 note 列进行排序。

2、在记录的 note 列相同的情况下,采用 b 列进行排序

什么时候需要用到联合索引呢

  1. 在这个索引排好序的基础上还需要对其他字段再次进行排序
  2. 多条件查询时,为了减少某些条件不在联合索引中而导致的回表查询操作
  3. 需要使用覆盖索引时(维护一个冗余索引减少回表操作)。

假的索引——覆盖索引/索引覆盖

为什么说这个索引是个假的索引呢?因为实际上这个覆盖索引的本质就是联合索引。因此覆盖索引相对于传统意义的索引而言,仅仅是一种思想。

用普通索引只查一个ID需要回表么

如果执行的语句是select ID from T where k between 3 and 5,这时只需要查ID的值,而ID的值已经在k索引树上了,因此可以直接提供查询结果,不需要回表。也就是说,在这个查询里面,索引k已经“覆盖了”我们的查询需求,我们称为覆盖索引。

由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。

用联合索引来实现覆盖索引

基于上面覆盖搜索的说明,我们来讨论一个问题:在一个市民信息表上,是否有必要将身份证号和名字建立联合索引?

假设这个市民表的定义是这样的:

CREATE TABLE `tuser` (`id` int(11) NOT NULL,`id_card` varchar(32) DEFAULT NULL,`name` varchar(32) DEFAULT NULL,`age` int(11) DEFAULT NULL,`ismale` tinyint(1) DEFAULT NULL,PRIMARY KEY (`id`),KEY `id_card` (`id_card`),KEY `name_age` (`name`,`age`)
) ENGINE=InnoDB

我们知道,身份证号是市民唯一的标识。也就是说,如果有根据身份证号查询市民信息的需求,我们主要在身份证号字段上建立索引就够了。而再建立一个 KEY `id_card_name` (`id_card`,`name`)(身份证号,姓名)的联合索引是不是浪费空间?

如果现在有一个高频请求,要根据市民的身份证号查询他的姓名,这个联合索引就有意义了。(联合索引的key同时包含他们两个字段)它可以在这个高频请求上用到覆盖索引,不再需要回表查询整行记录,减少语句的执行时间。

当然,索引字段的维护总是由代价的。因此,在建立冗余索引来支持覆盖索引时就需要权衡考虑了。这正是DBA,或者成为业务数据架构师的工作。

自适应哈希索引(热点监控索引)

热点普通索引数据新增Hash索引

InnoDB 存储引擎除了我们前面所说的各种索引,还有一种自适应哈希索引, 我们知道 B+树的查找次数,取决于 B+树的高度,在生产环境中,B+树的高度一般 为 3~4 层,故需要 3~4 次的 IO 查询。

所以在 InnoDB 存储引擎内部自己去监控索引表,如果监控到某个索引经常 用,那么就认为是热数据,然后内部自己创建一个 hash 索引,称之为自适应哈 希索引( Adaptive Hash Index,AHI)  :

Hash索引的优劣再分析

在之前我们分析MySQL底层数据结构时,对底层为什么不使用Hash结构进行了分析。

优点

创建以后,如果下次又查询到这个索引, 那么直接通过 hash 算法推导出记录的地址,很多时候查询效率都可以优化为O(1),比重复去 B+tree 索引中查询三四次节点的效率高了不少。在查询某个特定的值的情况中可以起到(概率性)加速的效果。

缺点

  1. 如我们之前分析的一样,hash表的特性就是随机散列带来的无序性,因此无法进行范围查询。因此自适应哈希索引能发挥效果的场景比较局限。只能用于等值比较,例如=, <=>,in。
  2. hash自适应索引会占用innodb buffer pool;
  3. 极端情况下,自适应hash索引才有比较大的意义,可以降低逻辑读。

自适应哈希索引功能的开关(默认开启)

mysql> show variables like '%ap%hash_index';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| innodb_adaptive_hash_index | ON    |
+----------------------------+-------+
1 row in set (0.01 sec)

可以通过 show variables like '%ap%hash_index';语句查看是否开启此索引功能

默认开启,建议关掉,意义不大。可以通过 set global innodb_adaptive_hash_index=off/on 关闭和打开该功能。

如何判断是否什么时候需要自适应Hash索引

通过命令 show engine innodb status\G 可以看到当前自适应哈希 索引的使用状况:

  1. 34673:字节为单位,占用内存空间总量
  2. 通过hash searches、non-hash searches计算自适应hash索引带来的收益以及付出,确定是否开启自适应hash索引

全文检索之倒排索引

什么是全文检索(Full-Text Search)?它是将存储于数据库中的整本书或整 篇文章中的任意内容信息查找出来的技术。它可以根据需要获得全文中有关章、 节、段、句、词等信息,也可以进行各种统计和分析。我们比较熟知的 Elasticsearch、 Solr 等就是全文检索引擎,底层都是基于 Apache Lucene 的。

举个例子,现在我们要保存唐宋诗词,数据库中我们们会怎么设计?诗词表 我们可能的设计如下:

要根据朝代或者作者寻找诗,都很简单,比如“select 诗词全文 from 诗词表 where 作者=‘李白’”,如果数据很多,查询速度很慢,怎么办?我们可以在 对应的查询字段上建立索引加速查询。

倒排索引实例

但是如果我们现在有个需求:要求找到包含“望”字的诗词怎么办?

用 “select 诗词全文 from 诗词表 where 诗词全文 like‘%望%’”,这个意味着 要扫描库中的诗词全文字段,逐条比对,找出所有包含关键词“望”字的记录,。 基本上,数据库中一般的 SQL 优化手段都是用不上的。数量少,大概性能还能接 受,如果数据量稍微大点,就完全无法接受了,更何况在互联网这种海量数据的 情况下呢?怎么解决这个问题呢,用倒排索引

假设现在有四首诗,每首诗都包含"望"这个词,那么我们可以自己这样建立一张表来存储对应关系:

如果查哪个诗词中包含上,怎么办,上述的表格可以继续填入新的记录:

总结什么是倒排索引

其实,上述诗词的中每个字都可以作为关键字,然后建立关键字和文档之间的对应关系,也就是标识关键字被哪些文档包含。

所以,倒排索引就是,将文档中包含的关键字全部提取处理,独立维护一张关键字与诗名的对应关系表。在之后的查询时,可以根据我们之前维护的这张表进行查询。

MySQL自己写倒排索引所带来的麻烦

在存储在关系型数据库中的数据,需要我们事先分析将数据拆分为不同的字段,而在 es 这类的存储中,需要应用程序根据规则自动提取关键字,并形成对应关系。这些预先提取的关键字,在全文检索领域一般被称为 term(词项),文档的词项提取在 es 中被称为文档分析,这是全文检索很核心的过程,必须要区分 哪些是词项,哪些不是,比如很多场景下,apple 和 apples 是同一个东西,"望"和"看"其实是同一个动作。

存储引擎与专业检索引擎的区别

从 InnoDB 1.2.x 版本开始,InnoDB 存储引擎开始支持全文检索,对应的 MySQL 版本是 5.6.x 系列。不过 MySQL 从设计之初就是关系型数据库,存储引擎虽然支持全文检索,整体架构上对全文检索支持并不好而且限制很多,比如每张表只能有一个全文检索的索引,不支持没有单词界定符( delimiter)的语言, 如中文、日语、韩语等。

所以如果有大批量或者专门的全文检索需求,还是应该选择专门的全文检索引擎,毕竟 Elastic 靠着全文检索起家,然后产品化、公司化后依赖全文检索不断 扩充产品线和应用场景,并推出商业版本的解决方案然后融资上市,现在的市值已达 100 亿美元(2021/03/24-纽约证券交易所中的市值 99.84 亿美元)。

具体如何使用 InnoDB 存储引擎的全文检索,请自行查阅相关官方文档或者书籍,我们不做任何讲解和技术支持。

MySQL的核心之InnoDB中的花式索引相关推荐

  1. mysql vpformysql引擎_MySQL InnoDB引擎B+树索引简单整理说明

    本文出处:http://www.cnblogs.com/wy123/p/7211742.html (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错 ...

  2. mysql的学习要点_MySQL中的联合索引的学习要点总结

    MySQL中的联合索引的学习要点总结 联合索引又叫复合索引.对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分.例如索引是key index (a ...

  3. python花式索引_初探Numpy中的花式索引

    Numpy中对数组索引的方式有很多(为了方便介绍文中的数组如不加特殊说明指的都是Numpy中的ndarry数组),比如:基本索引:通过单个整数值来索引数组 import numpy as np arr ...

  4. 【Mysql】InnoDB 中 B+ 树索引的注意事项

    一.根页面万年不动 在之前的文章里,为了方便理解,都是先画存储用户记录的叶子节点,然后再画出存储目录项记录的内节点. 但实际上 B+ 树的行成过程是这样的: 每当为某个表创建一个 B+ 树索引,都会为 ...

  5. oracle索引与mysql区别_MySQL和Oracle中的唯一性索引从差别(r12笔记第83天)

    今天在修复MySQL数据的时候,发现一个看起来"奇怪"的问题. 有一个表里存在一个唯一性索引,这个索引包含3个列,这个唯一性索引的意义就是通过这3个列能够定位到具体1行的数据,但是 ...

  6. MySQL(四)InnoDB中一棵B+树能存多少行数据

    一.InnoDB一棵B+树可以存放多少行数据?(约2千万) 我们都知道计算机在存储数据的时候,有最小存储单元,这就好比我们今天进行现金的流通最小单位是一毛.在计算机中磁盘存储数据最小单元是扇区,一个扇 ...

  7. mysql临键锁_详解 MySql InnoDB 中的三种行锁(记录锁、间隙锁与临键锁)

    详解 MySql InnoDB 中的三种行锁(记录锁.间隙锁与临键锁) 前言 InnoDB 通过 MVCC 和 NEXT-KEY Locks,解决了在可重复读的事务隔离级别下出现幻读的问题.MVCC  ...

  8. 面试必问:InnoDB 中一棵 B+ 树能存多少行数据?

    一.InnoDB一棵B+树可以存放多少行数据? InnoDB一棵B+树可以存放多少行数据?这个问题的简单回答是:约2千万.为什么是这么多呢?因为这是可以算出来的,要搞清楚这个问题,我们先从InnoDB ...

  9. 面试:InnoDB 中一棵 B+ 树可以存放多少行数据?

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源:cnblogs.com/leefreeman/p/ ...

最新文章

  1. 【Android】Android中使用JNI调用底层C++代码
  2. ORACLE初始化参数文件概述
  3. 超级简洁的xml解析框架:TBXML
  4. 胡学纲数据结构c语言PDF,数据结构精品课程参考书目
  5. Ubuntu 定时开关机
  6. Word中插入的域或者公式显示乱码的解决办法
  7. 【L2TP】L2TP IPsec设置
  8. html用于定义表格行的标签,HTML表格标签
  9. 计算机上无线网络开关在哪里,笔记本无线网络开关在哪里
  10. 用Python从《诗经》中取平仄相对的名字
  11. APIO2019 打铁记
  12. linux控制wifi发射功率,路由器的发射功率上限是多少
  13. Windows中Redis的下载安装与修改密码并启动
  14. uva10158(并查集)
  15. 阿里云MQTT_Password工具下载地址
  16. 计算机是如何读懂高级语言的——编译过程简述
  17. 赴美生子入境经验汇总
  18. Android动画之视图动画和属性动画
  19. 高通骁龙845的android手机有哪些,2018年骁龙845手机有哪些?骁龙845手机怎么样?...
  20. 软考A计划-重点考点-专题十二(JAVA程序设计)

热门文章

  1. ServletFileUpload、MultipartRequest与MultipartParser的区别
  2. alias cp的使用
  3. android代码混淆详解
  4. 给你的Blog添加经典言论引用
  5. Leetcode第一题,c_oop宇宙诞生秘要珍宝
  6. [转载]《星际争霸》单位语音中英文完全版
  7. 服务器液冷散热与风冷散热
  8. 网站选域名:大量情侣网站
  9. 微人事项目视频教程已经开始更新,国庆节有事情做啦!
  10. java itext 里表格_Java使用itext5实现PDF表格文档导出