一、数据库索引介绍
数据库索引
索引是加速表的查询效率而创建的数据结构
日常场景:新华字典的目录类似一个索引。
构造一个索引过程例子
user_id/索引列 | 磁盘地址 | 磁盘地址 | order_id/主键 | user_id | shop_id | create_time | status | amount | delivery_amount | |
1000 | 0x01 | 0x01 | 1 | 1000 | 7567 | 2/19/2020 13:56 | 1 | 100 | 2 | |
4000 | 0x04 | 0x02 | 2 | 6700 | 7670 | 2/19/2020 13:56 | 1 | 101 | 3 | |
5643 | 0x03 | 0x03 | 3 | 5643 | 3450 | 2/19/2020 13:56 | 1 | 102 | 4 | |
6700 | 0x02 | 0x04 | 4 | 4000 | 5660 | 2/19/2020 13:56 | 1 | 103 | 5 | |
6700 | 0x05 | 0x05 | 5 | 6700 | 4356 | 2/19/2020 13:56 | 1 | 104 | 6 | |
8880 | 0x06 | 0x06 | 6 | 8880 | 4356 | 2/19/2020 13:56 | 1 | 105 | 7 |
● 索引是一个有序结构
○ 有序的结构可以提高查找的效率【不仅仅可以采用二分查找,可以构造多叉有序结构提高查找效率】
○ 无序的结构的查找需要遍历
● 索引可以减少存储引擎(MYSQL)的查询数据量
○ 索引是有序结构、避免了全表扫描
○ 索引列少,占用的存储量少
● 将随机IO变成有序IO
○ 业务写入是无序的、从有序的结构中检索
○ 一般而言,无序的东西是没有价值的。【将随机变成有序是一种架构】
○ 写性能和读性能的平衡(架构)、并发处理的解决方案
● 提高分组、排序效率,避免使用临时表
○ 对有序结构遍历就可以完成分组、排序
○ 全表扫描、内存不够就需要使用临时表
二、Hash索引的原理和应用
通过元素的Hash函数直接计算出元素的地址的索引。
- Hash(4000)=0x04
- 实际上这种算法是不存在的
真实的Hash索引是基于Hash表的数据结构
Hash表的基础结构
● 数组 例子中有13个元素、
○ 对元素进行分治分桶处理。
○ 数组可以快速的通过下标定位元素。
● 链表 例子中是向上的结构
○ 处理元素Hash碰撞导致的数组地址重复问题
● Hash算法
○ 计算元素在数组中的位置坐标。
○ 常见的Hash算法
● 第一步 元素(字符串)Hash运算取整
● Hash整数对数组取余
Hash索引的应用场景
● 数据结构中使用HashMap
● 小数据量的内存索引中
● 内存数据库中会使用Hash索引
● INNODB也是使用Hash索引
三、B树、B+树结构和应用场景
B树、B+树 多路树、多二叉树的扩展。
B树、B+树 数据结构的差异
● B+树最末端叶子节点包含所有的元素、B树是整棵树包含所有的元素
● B+树的最末端叶子节点是链表
user_id/索引列 | 磁盘地址 | 磁盘地址 | order_id/主键 | user_id | shop_id | create_time | status | amount | delivery_amount | |
1000 | 0x01 | 0x01 | 1 | 1000 | 7567 | 2/19/2020 13:56 | 1 | 100 | 2 | |
4000 | 0x04 | 0x02 | 2 | 6700 | 7670 | 2/19/2020 13:56 | 1 | 101 | 3 | |
5643 | 0x03 | 0x03 | 3 | 5643 | 3450 | 2/19/2020 13:56 | 1 | 102 | 4 | |
6700 | 0x02 | 0x04 | 4 | 4000 | 5660 | 2/19/2020 13:56 | 1 | 103 | 5 | |
6700 | 0x05 | 0x05 | 5 | 6700 | 4356 | 2/19/2020 13:56 | 1 | 104 | 6 | |
8880 | 0x06 | 0x06 | 6 | 8880 | 4356 | 2/19/2020 13:56 | 1 | 105 | 7 |
B+树索引的优良特性
● B系列树的多路特性(节点可以容纳更多的关键字、元素)、整棵树的层级会非常浅、可以充分利用操作系统的分页读取特性(Linux操作系统每次读取4KB页数据、MYSQL每页是16KB)、可以将索引单节点完全加载到内存。
● B+树非最末端叶子节点只需要存储下级节点的地址(指针)、B+树的非末端叶子节点每页可以容纳更多的关键字(元素)、B树还要存储数据、B+树的非末端叶子节点可以容纳多少元素是可以被计算出来的。
● B+树的最末端叶子节点是链表、如果你需要遍历,只需要顺序读取就可以了。
B+树的应用场景
● 数据库的索引
● 大数量的场景都可以作为快速查找的目录结构
四、二叉树结构和索引的关系
常见的有序二叉树
● 二叉查找树 极端情况会退化成链表、丧失平衡性、无法体现二分查找的优越性【LogN】
● AVL树 完美平衡的树、但是自平衡效率非常低
● 红黑树 非完美平衡的树、黑色完美平衡的树、自平衡效率优良
二叉树结构不适合数据库索引原因
● 节点稀疏 一个节点只有一个元素(关键字)、很难利用操作系统页读取和存储的特性
● 节点深100万的二叉树结构,层级至少为20以上【20次的IO对于数据库而言是灾难性的】
● 二叉树结构难以连续的读取
二叉树结构的应用场景
● 非数据密集型的小数据集场景
○ 红黑树HashMap数据结构中
○ Linux NIO Epoll网络编程模型 使用了红黑树结构
二叉树结构对数据库索引的启发关系
● 减少层级
● 增加页内元素的数量
● 叶子结点使用双向链表的结构
五、InnoDB聚簇索引原理
MySQL聚簇索引
聚簇索引定义:行数据存放在B+树索引的叶子节点上。一般而言聚簇索引和主键索引是相同的。
聚簇索引是表记录的存储方式。使用聚簇索引的表叫索引组织表。
MySQL InnoDB 存储引擎使用的就是索引组织表。
通俗的将聚簇索引理解为数据和索引聚集在一起的索引。
构造MySQL聚簇索引
● 第一步 使用主键列构造B+树结构
● 第二步 将表的行记录添加到B+树的叶子节点上
六、InnoDB聚簇索引性能优化
聚簇索引的构造原理
● MySQL聚簇索引默认使用主键索引
● MySQL聚簇索引会使用非空唯一键索引
● 没有主键索引、非空唯一键索引。INNODB会在表的列中增加ROWID列作为隐形主键
聚簇索引性能优化
使用INNODB的自增ID作为主键。
● MySQL INNODB 的每张表都要有一个自增的主键【被推荐】【顺序递增的主键索引一般而言是追加操作】
● UUID主键、随机数主键【不推荐】【乱序的主键、索引要分裂节点、移动最末端叶子节点内的元素】
● 不推荐使用多列的组合主键【ABCDEFG7列,使用ABC三列主键,组合主键会增加索引的稀疏度,增加磁盘的存储】
七、InnoDB可以存储多少行数据
B+树、聚簇索引、索引组织表。
高性能的索引组织表 要求B+树深度不大于3(每次索引读取只需要3次IO)。
计算3层B+树可以存多少行表数据
第一层 16K=131072bit 关键字为64bit的整型,关键字下层的页指针64bit,第一层可以存储131072 / 128=1024页
第二层 可以存储1024*1024=1048576页
第三层 大约可以存储1048576*16=16777216行记录。假设一行表记录大小是1KB,每页可以存储16行记录。
MYSQL Innodb理论的行数是一千多万。实际工作中,MySQL Innodb每张表不要超过500万。
八、InnoDB辅助索引原理
除聚簇索引之外创建的索引
● 单列索引 只有一个列的辅助索引
● 联合索引 有多个列的辅助索引
● 唯一键索引 多了一个唯一性约束、可以是单列索引、联合索引
InnoDB 辅助索引的特点
● 辅助索引的索引值是主键,不是表记录的地址(指针)
● 使用innoDB辅助索引检索的时候需要进行两次索引的查询。
● 两次索引的查询过程:先读取辅助索引,再读取聚簇索引(主键索引)。
九、MyISAM非聚簇索引
MyISAM存储引擎、Oracle关系型数据库。
表行数据和索引是分开存储的。使用非聚簇索引存储结构的表叫堆表。【分为索引文件和数据文件】
优点:
● 表的写入速度会非常快【采用无序追加的方式写数据】
● 表的记录数可以容纳更多,三层非聚簇索引B+树可以容纳1073741824行数据。【公式1024的三次方】
构造一个非聚簇索引
● 表行记录数据还是分页存储,每页16K
● B+树索引的每个节点分页存储,每页16K