第5章 索引与算法
索引是应用程序设计和开发的一个重要方面,
索引过多或过少都不是好的设计,如何设计数据库达到一个平衡点是门艺术。
实际生产中,开发人员总是事后才想起添加索引,这是错误的开发模式。
DBA往往不了解业务,事后想添加索引需要耗费时间去监控大量的SQL语句,
在这种现实背景下,开发人员最应当作出改变,去了解索引,不仅知道数据的使用,
也知道在何处添加索引。
5.1 InnoDB存储引擎索引概述
该引擎支持三种索引:
B+索引
哈希索引
全文索引
注意:hash索引机制是自适应的,不能人为生成。
B+树索引不能找到具体的行,只能找到数据行所在的页。
然后把页读入内存,在内存中进行查找具体数据行。
5.2 数据结构与算法
(B+树索引是最常见的索引数据结构与算法)
5.2.1 二分查找法
记录内部有序,通过每次和中间值比较,跳跃式查找,
每次缩减一半的范围,快速找到目标的算法。其算法复杂度为log2(n)
5.2.2 二叉查找树和平衡二叉树
二叉查找树:
二叉查找树中,左子树的键值总小于根的键值,
右子树的键值总大于根的键值。
平衡二叉树:
先符合二叉查找树的定义,
其次满足任何节点的两个子树的高度最大差为1,
若不满足需要通过一次或多次左旋和右旋来达到树新的平衡。
二叉树多用于内存结构对象中,因此维护的开销相对较小。
5.3 B+树
(Balance查找树,为磁盘等直接存取设备服务)
在B树上增加规定:
叶子结点存数据,非叶子结点存指针
所有叶子结点从左到右用双向链表记录
内部排列:
所有的记录都按键值的大小放在同一层的叶子节点上,
各叶子节点之间有指针进行连接(非连续存储),形成一个双向链表。
索引节点按照平衡树的方式构造,
并存在指针指向具体的叶子节点,进行快速查找。
5.3.1 B+树的插入操作
B+ 树的插入必须保证插入后子节点中的记录依然排序
(为了保持平衡可能需要做大量的拆分页(spit)操作
通常情况下,左兄弟会被首先检查用来旋转操作
优势:旋转操作使 B+ 树减少了一次页的拆分操作
5.3.2 B+树的删除操作
B+ 树使用填充因子(fill factor)来控制树的删除变化
50% 是填充因子可设的最小值
B+ 树的删除操作同样也必须保证删除后的叶子节点中的记录依然排序
5.4 B+树索引
(B+ 树索引的本质就是B+ 树在数据库中的实现)
高扇出性(B+ 树的高度一般都在 2 ~ 4 层,查找某一键值只需要 2 到 4次 IO
B+ 树索引可以分为 聚集索引(聚簇索引) 和 辅助索引(二级索引)
其内部都是B+ 树,即高度平衡,叶子节点存放所有数据
不同的是,聚集索引叶子节点存储着整行记录数据,辅助索引存储着聚集索引键值。
5.4.1 聚集索引
聚集索引就是按照表的主键构造一颗B+树,
叶子节点存放的是整张表的行记录,可直接找到数据。
将聚集索引的叶子节点称为数据页,数据按照主键顺序存放。
聚集索引的存储并不是物理上连续的,而是逻辑上连续的。
5.4.2 辅助索引
页内不包含行的全部数据,而是相应行数据的聚集索引键。
5.4.3 B+树索引的分裂
5.4.4 B+树索引的管理
1、SHOW INDEX命令得到结果的含义:
Table:索引所在的表名
Non_unique:如果显示的值是0,说明这个字段(列)是唯一索引,显示1表示非唯一索引
Key_name:索引的名字,用户可以通过这个名字来执行DROP INDEX
Seq_in_index:索引中该列的位置,单独一个列的索引就是1,如果复合索引就是从1开始递增
Column_name:索引列的名称(字段名)
Collation:列以什么方式存储在索引中,可以是A或者NULL。
B+树索引总是A,即排序的。
如果使用了Heap存储引擎,并且建立了Hash索引,这里的值就是NULL。
因为Hash根据Hash桶存放索引数据,而不是对数据排序
Cardinality:索引的区分度,应该尽可能接近于1。
Sub_part:是否是列的部分被索引。
Packed:关键字然后被压缩,如果没有被压缩则为NULL
NULL:是否索引的列含有NULL值,如果显示为Yes,则该列允许为NULL,如果留空没有值,则该列不允许NULL
Index_type:索引的类型,InnoDB存储引擎只支持B+树索引,都显示BTREE
Comment:列的注释
2、Fast Index Creation(FIC):快速索引创建
3、Online Schema Change(OSC):在线架构改变
5.5 Cardinality值
5.5.1 什么是Cardinality
一个评估值,用于评估列是否需要添加索引的指示器,
对应性别字段、地区字段等,他们均有低选择性特征。
给这些字段添加索引完全没有必要。
5.5.2 InnoDB存储引擎的Cardinality统计
在存储引擎层通过采样的方法来完成更新。
以下情况会更新Cardinality统计信息:
表中1/16的数据发生过变化
stat_modified_counter>2 000 000 000:发生变化的次数
5.6 B+树索引的使用
5.6.1 不同应用中B+树索引的使用
应用场景有:
OLTP:具体信息,一线业务。
通常给订单号等查找条件建立索引。
OLAP:宏观的信息,而不是微观。
通常会需要对时间字段进行索引,
因为大多数统计需要根据时间维度进行数据筛查。
5.6.2 联合索引
对表上多个列进行索引,并且按照索引的顺序在B+树上进行排序,
并且在orderby时如果按照索引的顺序排序,可以避免filesort。
注意:单独看后面的列,并没有按顺序摆放,索引将不起作用。
filesort是外部排序,可理解为使用状态机来实现归并排序,
发生在根据某一个没有添加索引的字段进行排序,效率低。
使用explian命令将在Extra中看到filesort。
5.6.3 覆盖索引
从辅助索引中就可以得到查询的记录,不需要查询聚集索引中的记录。
5.6.4 优化器选择不使用索引的情况
默认占比超20%会选择聚集索引(主键),放弃使用辅助索引。
当要检出数据量大时,优化器会选择(全表扫描,顺序读)。
在用固态硬盘(随机读快)并认为用辅助索引更快,可FORCE INDEX。
5.6.5 索引提示
若优化器错误地选择了某个索引,导致 SQL 语句执行过慢,
可FORCE INDEX 用于强制指定某个索引完成查询。
5.6.6 Multi-Range Read优化
MRR 优化适用于 range、ref、eq_ref 类型的查询。
在查询辅助索引时,结果按照主键进行排序,在顺序查找聚集索引,
减少缓冲池中页被替换的次数,批量处理对键值的查询操作。
5.6.7 Index Condition Pushdown(ICP)优化
原理:存储引擎层过滤
当进行索引查询时,会在取出索引的同时过滤,减少了SQL层过滤
5.7 哈希算法
5.7.1 哈希表
自适应hash索引,不只存在于自适应hash中,
每个数据库中都存在,用来加速内存中数据的查找。
5.7.2 InnoDB存储引擎中的哈希算法
用于字典查找,哈希函数采用除法散列方法,
冲突机制采用链表方式。
5.7.3 自适应哈希索引(默认开启)
通过参数innodb_adaptive_hash_index来禁用或启动此特性。
属于数据库内部机制,DBA不能干预。
它只对字典类型的查找非常快速,而对范围查找无效。
5.8 全文检索
5.8.1 概述
使用倒排索引(inverted index)来实现。
MyISAM存储引擎一直支持,InnoDB1.2.x起支持。
5.8.2 倒排索引
使用辅助表,单词与单词自身在一个或多个文档中所在位置之间的映射。
通常利用关联数组实现。
5.8.3 InnoDB全文检索
三个限制:
1.只能有一个全文索引
2.全文检索索引必须相同的字符集和字符序
3.不支持没有单词界定符的语言,如中日韩语等
5.8.4 全文检索
两种方法:
自然语言(Natural Language)
默认方法,可省略:(IN NATURAL LANGUAE MODE)
布尔模式(Boolean Mode):(IN BOOLEAN MODE)
+: 该word必须存在
-: 该word必须排除
(no operator): 该word可选,如果出现,相关性更高
@distance: 查询的多个单词必须在指定范围之内
>: 出现该单词时增加相关性
<: 出现该单词时降低相关性
~: 出现该单词时相关性为负
*: 以该单词开头的单词
": 表示短语
5.9 小结
本章循序渐进学习了B+树、全文索引等原理,从数据结构入手,
通过讨论了索引的环境和优化方法,分析在一些业务情景中优化索引方案的依据。