InnoDB存储引擎索引概述、
innodb支持以下几种常见的索引:
- B+树索引
- 全文索引
- 哈希索引
innodb支持的哈希索引是自适应的,innodb会根据表的使用情况自动为表生成哈希索引,不能人为干预是否在一张表中生成哈希索引。
B+树索引就是传统意义上的索引,这是目前关系型数据库系统中查找最为常用和最有效的索引。
B+树中的B不是代表二叉(binary),而是代表平衡(balance),因为B+树是从最早的平衡二叉树演化而来。
B+树索引是先找到数据行所在的页。然后数据库通过把页读入到内存,再在内存中进行查找,最后得到要查找的数据
数据结构与算法
- 二分查找法
二分查找法(binary seach)也称为折半查找法,用来查找一组有序的记录数组中的某一记录,其基本思想是:将记录有序化(递增或递减)排列,在查找过程中采用跳跃式方式查找,即先以有序数列的中点位置为比较对象,如果要找的元素值小于该中点元素,则将待查序列缩小为左半部分,否则为右半部分。通过一次比较,将查找区间缩小一半。 - 二叉查找树和平衡二叉树
B+树是通过二叉查找树,再由平衡二叉树,B树演化而来。
平衡树的定义如下:首先符合二叉查找树的定义,其次必须满足任何节点的两个子树的高度最大差为1.
B+树
B+树是为磁盘或其他直接存取辅助设备设计的一种平衡查找树。在B+树中,所有记录节点都是按键值的大小顺序存放在同一层的页子节点上,由各页子节点指针进行连接。
- B+树的插入操作
B+树的插入操作有三种情况,如下图所示:
- B+树的删除操作
B+树使用填充因子来控制树的删除变化,50%是填充因子可设的最小值。B+树的删除也要考虑下图中的三种情况,与插入不同的是,删除根据填充因子的变化来衡量。
B+树索引
B+树索引在数据库中有一个特点是高扇出性,在数据库中,B+树的高度一半在2~4层,这也就是说查找某一键值的行记录最多只需要2到4次IO。
数据库的B+树索引可以分为聚集索引(clustered index)和辅助索引(secondary index),这两个索引内部都是B+树的,高度平衡的,叶子节点存放所有的数据。这两个索引不同点在于叶子节点存放的是否是一整行的信息。
聚集索引
聚集索引就是按照每张表的主键构造一棵B+树,同时叶子节点中存放的即为整张表的行记录数据,也将聚集索引的叶子节点称为数据页。这个特性决定了索引组织表中数据也是索引的一部分。同B+树数据结构一样,每个数据页都通过一个双向链表来进行链接。辅助索引
对于辅助索引(非聚集索引),叶子节点并不包含行记录的全部数据。叶子节点除了包含键值以外,每个叶子节点中的索引行还包含了一个书签,该书签用来告诉innodb哪里可以找到与索引相对应的行数据。由于innodb是索引组织表,innodb的辅助索引的书签是相应行数据的聚集索引键。B+树索引的分裂
innodb的Page Header有以下几个部分用来保存插入的顺序信息:- PAGE_LAST_INSERT
- PAGE_DIRECTION
- PAGE_N_DIRECTION
通过这些信息,innodb可以决定是向左还是向右进行分裂,同时决定将分裂点记录为哪一个。
B+树索引的管理
索引管理
索引的创建和删除可以通过两种方法,一种是ALTER TABLE,另一种是CREATE/DROP INDEX。Fast Index Creation(快速索引创建)
innodb1.0.x版本开始支持快速索引创建简称FIC。
对于辅助索引的创建,innodb会对创建索引的表加上一个S锁。在创建的过程中,不需要重建表,因此速度会很快,数据库的可用性也很不错。至于删除辅助索引,innodb只需要更新内部视图,并将辅助索引的空间标记为可用,同时删除mysql内部视图上对该表的索引定义即可。
临时表的创建路径是通过参数tmpdir进行设置的。用户必须保证tmpdir有足够的空间可以存放临时表,否则会导致创建索引失败。
Online Schema Change
Online Schema Change(在线架构改变,简称OSC)最早是由facebook实现的一种在线执行DDL的方式。’在线’指的是在事务的创建过程中,可以有读写事务对表进行操作,这提高了原有mysql数据库在DDL操作时的并发性。
实现OSC步骤如下:- init,初始化阶段,会对创建的表做一些验证工作
- createCopyTable,创建和原始表结构一样的新表
- alterCopyTable,对创建的新表进行ALTER TABLE操作,如添加索引或列等。
- createDeltasTable,创建deltas表,该表的作用是为下一步创建的触发器所用。之后对原表的所有DML操作会被记录到createDeltasTable中。
- crerateTriggers,对原表创建INSERT、UPDATE、DELETE操作的触发器。触发操作产生的记录被写入到deltas表。
- startSnpshotXact,开始OSC操作的事务
- selectTableIntoOutFile,将原表中的数据写入到新表。这里采用的是分片的方式将数据输出到多个外部文件。
- dropNCIndexs,在导入到新表前,删除新表中所有的辅助索引
- loadCopyTable将导出的分片文件导入到新表
- replayChanges,将OSC过程中原表DML操作的记录应用到新表中,这些记录保存在deltas表中。
- recreateNCIndexes,重新创建辅助索引
- replayChanges,再次进行DML日志的回放操作,这些日志是在上述创建辅助索引中过程中新产生的日志
- swapTables,将原表和新表交换名字,整个操作需要锁定2张表,不允许新的数据产生。
Online DDL
mysql5.6开始支持Online DDL(在线数据定义)操作,其允许辅助索引创建的同时,还允许其他诸如INSERT、UPDATE、DELETE这类DML操作,这极大提高了mysql在生产环境中的可用性。
以下几类DDL操作都可以通过’在线’方式进行操作:- 辅助索引的创建和删除
- 改变自增长值
- 添加或删除外键约束
- 列的重命名
Cardinality值
什么是Cardinality
Cardinality值非常关键,表示索引中不重复记录数量的预估值。Cardinality是一个预估值,不是一个准确值,基本上用户也得不到一个准确值。实际应用中Cardinality/n_rows_in_table应该尽可能接近1,如果非常小,那么需要考虑是否还有必要创建这个索引。InnoDB存储引擎的Cardinality统计
对Cardinality的统计是放在存储引擎层进行的。数据库对Cardinality的统计都是通过采样的方法完成的。在innodb中Cardinality统计信息的更新发生在两个操作中:INSERT和UPDATE。
innodb内部对更新Cardinality信息的策略为:- 表中1/16的数据已经发生过变化
- stat_modified_counter>2000000000
innodb1.2提供了更多参数对Cardinality统计进行设置,如下图所示:

B+树索引的使用
- 不同应用中B+树索引的使用
需要根据自己的具体生产环境来使用索引,并 观察索引使用的情况,判断是否需要添加索引。不要盲从任何人给的经验。 - 联合索引
联合索引是指对表上的多个列进行索引。从本质上来说,联合索引也是一棵B+树,不同的联合索引的键值的数量不是1,而是大于等于2. - 覆盖索引
覆盖索引是指从辅助索引中就可以得到查询的记录,而不需要查询聚集索引中的记录。覆盖索引可以减少大量的IO操作。 - 优化器选择不使用索引的情况
这种情况多发生于范围查找、JOIN链接操作等情况下。 - 索引提示
有以下两种情况可能用到索引提示(INDEX HINT):- mysql数据库的优化器错误的选择了某个索引,导致sql语句运行的很慢。
- 某个sql语句可以选择的索引非常多,这时优化器选择执行计划时间的开销可能会大于sql语句本身。
- Multi-Range Read优化
Multi-Range Read优化的目的是为了减少磁盘的随即访问,并且将随即访问转化为较为顺序的数据访问,这对于IO-bound类型的sql查询语句可带来性能的极大提升。Multi-Range Read优化可适用于range、ref、eq_ref类查询。
MRR优化有以下几个好处:- MRR使数据访问变得较为顺序。
- 减少缓冲池中页被替换的次数
- 批量处理对键值的查询操作
- Index Condition Pushdown(ICP)优化
在ICP支持下,mysql数据库会在取出索引的同时,判断是否可以进行WHERE条件的过滤,也就是将WHERE的部分过滤操作放在了存储引擎层。
ICP优化支持range、ref、eq_ref、ref_or_null类型的查询。
哈希算法
- 哈希表
哈希表也称为散列表,由直接寻址表改进而来。 - InnoDB中的哈希算法
innodb使用哈希算法来对字典进行查找,其冲突机制采用链表方式,哈希函数采用除法散列方式。 - 自适应哈希索引
自适应哈希索引经哈希函数映射到一个哈希表中,因此对于字典类型的查找非常快速,但对于范围查找就无能为力了。
全文检索
概述
全文检索是将存储于数据库中的整本书或整篇文章中的任意内容查找出来的技术。它可以根据需要获得全文中有关章、节、段、句、词等信息,也可以进行各种统计和分析。倒排索引
倒排索引在辅助表中存储了单词与单词自身在一个或多个文档中所在位置之间的映射。这通常利用关联数组实现,拥有两种表现形式:- inverted file index,其表现形式为{单词,单词所在文档的ID}
- full inverted index,其表现形式为{单词,(单词所在文档的ID,在具体文档中的位置)}
InnoDB全文检索
innodb全文检索技术采用full inverted index的方式。在innodb中,将(DocumentId, Position)视为一个“ilist”。全文检索表中有两个列,一个是word字段,另一个是ilist字段,且在word字段上设有索引。此外innodb在ilist中存放了Position信息,可以进行Proximity search。倒排索引需要将word存放到一张表中,这个表称为Auxiliary Table(辅助表)。为了提高全文检索的并行性能,innodb有6张Auxiliary Table,目前每张表根据word的Latin编码进行分区
Auxiliary Table是持久的表,存放于磁盘上。innodb采用FTS Index Cache(全文检索索引缓存)来提高全文检索的性能。FTS Index Cache是一个红黑树结构,其根据(word, ilist)进行排序。
全文检索
mysql通过MATCH()…AGAINST()语法支持全文检索的查询,MATCH指定了需要被查询的列,AGAINST指定了使用何种方法去进行查询。Natural Language
全文检索通过MATCH函数进行查询,默认采用Natural Language模式,其表示查询带有指定word的文档。
在WHERE条件中使用MATCH函数,查询返回的结果时根据相关性进行降序排序的,即相关性最高的结果放在第一位。相关性的值是一个非负的浮点数字,0表示没有任何相关性。相关性计算依据以下四个条件:- word是否在文档中出现
- word在文档中出现的次数
- word在索引列表中的数量
- 多少个文档包含该word
对于innodb的全文检索,还要考虑以下因素:
- 查询的word在stopwprd中,忽略该字符的查询
- 查询的word的字符长度是否在区间[innodb_ft_min_token_size, innodb_ft_max_token_size]内。
Boolean
mysql允许使用IN BOOLEAN MODE修饰符来进行全文检索。使用该修饰符时,查询字符串的前后字符会有特殊含义。
Boolean全文检索支持以下几种操作:-
+表示该word必须存在 -
-表示该word必须被排除 -
(no operator)表示该word是可选的 -
@distance表示查询的多个单词之间的距离是否在distance之内,distance的单位是字节。 -
>表示出现该单词时增加相关性 -
<表示出现该单词时降低相关性 -
~表示允许出现该单词,但是出现时相关性为负。 -
*表示以该单词开头的单词。如lik*,表示可以是lik,like或者likes -
"表示短语
-
Query Expansion
通过查询短语中添加WITH QUERY EXPANSION或IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION可以开启blind query expansion(又称为automatic relevance feedback)。该查询分为两个阶段:- 第一阶段:根据搜索的单词进行全文索引查询。
- 第二阶段:根据第一阶段产生的分词再进行一次全文检索的查询。