浅谈MySQL(一):存储引擎与索引
一、存储引擎
可以使用 show engines
命令显示当前版本有关的存储引擎的状态信息。
可以看到,我们默认的引擎是InnoDB。常用的还有MyISAM。本文主要介绍这两种引擎。
InnoDB
-
使用场景:一般都使用,只有在需要它不支持的特性时,才考虑使用其它存储引擎。
-
特性:
-
实现了四个标准的隔离级别
-
Read Uncommitted( 未提交读 )
可以读取其它事务修改但未提交的数据,会造成“脏读”、“幻读”和“不可重复读取”。
-
Read Committed (提交读)
只可读取其它事务修改并已经提交的数据。避免了“脏读”,不能避免“幻读”和“不可重复读取”。
-
Repeatable Read (可重复读)【默认级别】
锁定已经读的数据,当前事务提交前其它事务不允许修改。虽然避免了“脏取”和“不可重复读取”的情况,不能避免“幻读”,但造成了的性能损失。
可通过多版本并发控制(MVCC)+ Next-Key Locking 防止“幻读”。
-
Serializable (可串行化)
读取前锁定所有要读取的数据,当前事务提交前,其它事务不允许修改。最严格的级别,事务串行执行,资源消耗最大。
-
-
主索引是聚簇索引,在索引中保存了数据,从而避免直接读取磁盘,因此对查询性能有很大的提升。
-
内部优化,磁盘读取数据时采用的可预测性读、能够加快读操作并且自动创建的自适应哈希索引、能够加速插入操作的插入缓冲区等。
-
支持真正的在线热备份。其它存储引擎不支持在线热备份,要获取一致性视图需要停止对所有表的写入,而在读写混合场景中,停止写入可能也意味着停止读取。
-
MyISAM
-
使用场景:并发相对较低,且对查询性能要求极高且没有事务的需求时
-
特性:
- 支持压缩表和空间数据索引。
- 不支持事务
- 不支持行级锁,只能对整张表加锁。读取时会对需要读到的所有表加共享锁,写入时则对表加排它锁。但在表有读取操作的同时,也可以往表中插入新的记录,这被称为并发插入(CONCURRENT INSERT)。
- 读写互相阻塞,不仅会在写入的时候阻塞读取,还会在读取的时候阻塞写入,但读本身并不会阻塞另外的读
- 只会缓存索引,可以通过key_buffer缓存以大大提高访问性能减少磁盘IO,但是这个缓存区只会缓存索引,而不会缓存数据
- 崩溃后恢复速度与数据量大小成正比
- 崩溃后会造成索引损坏。
二、索引
1、B+Tree 索引
B+Tree是一种优化了的B-Tree ,所以我们先要了解B-Tree是什么
B-Tree
多路自平衡查找树
B的含义
鲁道夫·拜尔(Rudolf Bayer)和 艾华·M·麦克雷(Ed M. McCreight)于1972年在波音研究实验室(Boeing Research Labs)工作时发明了B 树,但是他们没有解释B 代表什么意义(如果有的话)。道格拉斯·科默尔(Douglas Comer)解释说: 两位作者从来都没解释过B树的原始意义。正如我们所见,“balanced”, “broad” 或 “bushy” 可能适合。其他人建议字母“B”代表 Boeing。源自于他的赞助,不过,看起来把B树当作“Bayer”树更合适些
高德纳(Donald Knuth) 在他1980年5月发表的题为“CS144C classroom lecture about disk storage and B-trees”的论文中推测了B树的名字取义,提出“B”可能意味Boeing 或者Bayer 的名字。
那我们都知道二叉查找树的时间复杂度是 O (logN),已经很快了,为什么还要用B-Tree呢?
重点在于磁盘 IO的次数。
磁盘的IO是非常耗费时间的,即使是使用PCIe总线支持NVMe协议的SSD。比起读内存的速度也是小巫见大巫了。
所以我们的操作系统对此进行了优化,每次读磁盘,就把当前地址的临近地址数据也取到内存中,称为一页,这样也减少了IO的次数。
那么当我们使用二叉查找树作为索引时,在最坏情况下,如果一页对应一个树节点,那么,磁盘IO的次数就等于树的高度。
在索引量大的时候,树会非常高,因此,为了减少IO的次数,我们需要尽可能的把树 “压扁”。B-Tree就这样诞生了。
B-Tree的定义
根据 Knuth 的定义,一个 m 阶的B树是一个有以下属性的树:
- 每一个节点最多有 m 个子节点
- 每一个非叶子节点(除根节点)最少有 ⌈m/2⌉ 个子节点
- 如果根节点不是叶子节点,那么它至少有两个子节点
- 有 k 个子节点的非叶子节点拥有 k − 1 个键
- 所有的叶子节点都在同一层
根据B-Tree的定义,虽然查找一个同样的索引,B-Tree在比对次数上与二叉查找树相差无几,但是B-Tree所有的比对操作都是发生在内存中的,而相同数量Key在B树中生成的节点,远远少于二叉查找树中的节点,这样磁盘IO的次数一下就降低了许多。
B+Tree
B+树一种对文件系统,索引优化了的B树
定义
- 在B+树中,具有n给关键字的结点含有n个分支。(B树中是n+1个,空位置引出1)
- 在B+树中,每个结点(除根结点以外)中的关键字个数 n 的取值范围为(m/2↑<=n<=m),根结点的取值范围为2<=n<=m
- 在B+树中叶子结点包含信息,并且包含了全部关键字,叶子结点引出的指针指向数据
- 在B+中有一个指针指向关键字最小的叶子结点,所有叶子结点链接成一个线性链表
那么为什么InnoDB选择了B+树呢?
最主要的原因是:B+ 树的所有叶节点可以通过指针相互连接,能够减少顺序遍历时产生的额外随机 I/O
这使得B+树对于OLTP(Online Transaction Processing)场景来说能够解决大多数问题。
2、全文索引
从文本或数据库中,不限定资料字段,自由地萃取出消息的技术。
倒排索引
Inverted index 是一种索引方法,被用来存储在全文索引下某个单词在一个文档或者一组文档中的存储位置[映射
有两种不同的反向索引形式:
- 一条记录的水平反向索引(或者反向档案索引)包含每个引用单词的文档的列表,表现为 {单词,单词所在文档ID}
- 一个单词的水平反向索引(或者完全反向索引)又包含每个单词在一个文档中的位置,表现为{单词,(单词所在文档ID, 文档中的位置)}
例:下面是要被索引的文本
- T0 =
"it is what it is"
- T1 =
"what is it"
- T2 =
"it is a banana"
可以得到的反向档案索引:
"a": {2}
"banana": {2}
"is": {0, 1, 2}
"it": {0, 1, 2}
"what": {0, 1}
检索的条件"what"
, "is"
和 "it"
将对应:{0,1} ∩ {0,1,2} ∩ {0,1,2} = {0,1},即在T0和T1文档中出现。
同样,我们也可以得到它的完全反向索引:
"a": {(2, 2)}
"banana": {(2, 3)}
"is": {(0, 1), (0, 4), (1, 1), (2, 1)}
"it": {(0, 0), (0, 3), (1, 2), (2, 0)}
"what": {(0, 2), (1, 0)}
由文档数量和当前查询的单词结果组成的的成对数据)。 同样,文档数量和当前查询的单词结果都从零开始。所以,"banana": {(2, 3)}
就是说 "banana"在T2中,而且在T2的位置是地址为3的单词。
如果我们执行短语搜索"what is it"
我们得到这个短语的全部单词各自的结果所在文档为T0和T1。但是这个短语检索的连续的条件仅仅在T1得到。
注:即使要插入的文档非常小,也可能会导致在辅助索引表中进行大量的小插入,所以InnoDB 使用全文索引缓存 ( cache ) 来临时缓存最近要插入到辅助索引表中的行。此内存缓存结构会一直持有插入的数据,直到缓存已满,然后批量将它们刷新到辅助索引表 )。
3、哈希索引
哈希索引能以 O(1) 时间进行查找,但是失去了有序性
哈希索引基于哈希表实现,只有精确匹配索引的所有列的查询才有效。
InnoDB 存储引擎有一个特殊的功能叫“自适应哈希索引”,当某个索引值被使用的非常频繁时,会在 B+Tree 索引之上再创建一个哈希索引,这样就让 B+Tree 索引具有哈希索引的一些优点,比如快速的哈希查找。
4、空间数据索引
MyISAM的空间数据索引基于R-Tree实现,用于地理数据存储。它会从所有维度来索引数据,可以有效地使用任意维度来进行组合查询。
测绘相关 本文不进行讨论