作为数据库文件系统都是用B-Tree或者B+Tree作为存储结构;因为 B+ 树是从最早的平衡二叉树演化而来的。B+ 树是由二叉查找树、平衡二叉(AVLTree)和平衡多路查找树(B-Tree)逐步优化而来。
B-Tree
平衡多路查找树(B-Tree):为磁盘等外存储设备设计的一种平衡查找树。系统从磁盘读取数据到内存时是以磁盘块(block)为基本单位的,位于同一磁盘块中的数据会被一次性读取出来,而不是按需读取。
InnoDB 存储引擎使用页作为数据读取单位,页是其磁盘管理的最小单位,
InnoDB 默认 page 大小是 16k。
系统的一个磁盘块的存储空间往往没有这么大,因此 InnoDB 每次申请磁盘空间时都会是若干地址连续磁盘块来达到页的大小 16KB。InnDB 在把磁盘数据读入到磁盘时会以页为基本单位,在查询数据时如果一个页中的每条数据都能助于定位数据记录的位置,这将会减少磁盘 I/O 的次数,提高查询效率。
B-Tree 结构的数据可以让系统高效的找到数据所在的磁盘块。
p.png
每个节点占用一个盘块的磁盘空间,一个节点上有两个升序排序的关键字和三个指向子树根节点的指针,指针存储的是子节点所在磁盘块的地址。
两个关键词划分成的三个范围域对应三个指针指向的子树的数据的范围域。
以根节点为例,关键字为 17 和 35,P1 指针指向的子树的数据范围为小于 17,P2 指针指向的子树的数据范围为 17~35,P3 指针指向的子树的数据范围为大于 35。
-
算法
在B-Tree中按key检索数据的算法非常直观:首先从根节点进行二分查找,如果找到则返回对应节点的data,否则对相应区间的指针指向的节点递归进行查找,直到找到节点或找到null指针,前者查找成功,后者查找失败。
模拟查找关键字 29 的过程:
- 根据根节点找到磁盘块 1,读入内存。[磁盘 I/O 操作第 1 次]
- 比较关键字 29 在区间(17,35),找到磁盘块 1 的指针 P2。
- 根据 P2 指针找到磁盘块 3,读入内存。[磁盘 I/O 操作第 2 次]
- 比较关键字 29 在区间(26,30),找到磁盘块 3 的指针 P2。
- 根据 P2 指针找到磁盘块 8,读入内存。[磁盘 I/O 操作第 3 次]
- 在磁盘块 8 中的关键字列表中找到关键字 29。
-
问题
在 B-Tree 中,每个节点中有 key,也有 data,而每一个页的存储空间是有限的,如果 data 数据较大时将会导致每个节点(即一个页)能存储的 key 的数量很小。
当存储的数据量很大时同样会导致 B-Tree 的深度较大,增大查询时的磁盘 I/O 次数,进而影响查询效率。
B+Tree
在 B+Tree 中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储 key 值信息,这样可以大大加大每个节点存储的 key 值数量,降低 B+Tree 的高度。
MySQL 的 InnoDB 存储引擎在设计时是将根节点常驻内存的,因此力求达到树的深度不超过 3,也就是说 I/O 不需要超过 3 次。
与B-Tree不同之处
- 数据是存在叶子节点中的;
- 数据节点之间是有指针指向的。
MyISAM 索引
MyISAM存储引擎文件有三个
- .frm 定义文件
- .MYD 数据文件
- .MYI 索引文件
使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址,通过索引只能找到地址还需要一次地址访问获取数据;
20160905170450409.png
InnoDB 索引
InnoDB存储引擎文件有二个
- .frm表的定义文件
- .idb是数据文件
InnoDB支持行锁,但行锁是在命中索引的情况下才会起作用。
表数据文件本身就是按b+tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此innodb表数据文件本身就是主索引
哪种可以使用到索引:
- 全值匹配
- 联合索引匹配最左前缀的查询
- 匹配列前缀
- 精确匹配左前列,并范围匹配另外一列
order_sn > '2017081212365897847' - 只访问索引,不需要数据行
限制
- 不按照最左列开始查找
- 不能跳过索引左边的列
- not in 和 <> 操作无法使用索引
- 查询某个列的范围,那么右边的列就不能使用索引
- 索引上使用表达式或者函数
- innodb 索引<767字节
- 前缀索引和索引列的宽度
- 索引选择性= 不重复索引值/表记录数比值
- 联合索引
- 经常用到的列,放到左边,status 这种列不一定使用索引
- 选择性高的列
- 宽度小的列
- 覆盖索引
能通过检索索引就可以读取想要的数据,那就不需要再到数据表中读取行了。如果一个索引包含了(或覆盖了)满足查询语句中字段与条件的数据就是覆盖索引
- 全部字段,出现在orderby group by
- 可以优化缓存,减少io操作
- 减少随机io,改为顺序io
- 避免对innodb主键索引的二次查询
总结:
MyISAM
- 主键索引/非主键索引
叶子节点上均带有地址,通过地址获取数据
InnoDB
- 主键索引(聚簇索引) 叶子节点上带有数据
- 非主键索引(第二索引) 叶子节点上带有主键id,需要再进行一次IO
网友评论