数据库笔记
索引
索引的定义
索引是帮助MySQL高效获取数据的排好序的数据结构
索引数据结构
二叉搜索树🔍
1. 定义
根据二叉搜索树的定义(左小右大),建立索引
-
key —— 索引的值
-
value —— 数据项的内存地址
2. 缺点
在key单调的情况下,会退化为链表结构,不使用
3. 结构图
hash结构
1. 定义
对索引进行哈希得到存储位置
2. 特点
•对索引的key进行一次hash计算就可以定位出数据存储的位置
•很多时候Hash索引要比B+ 树索引更高效
•仅能满足 “=”,“IN”,不支持区间查询 【使用B+树的原因】
•hash冲突问题
3. 结构图
B树🔍
1. 定义
是一颗多路平衡查找树🔍,节点存储数据和索引
2. 特点
- 有序性 —— 节点中的数据索引从左到右递增排列
- 唯一性 —— 所有索引元素不重复
- 叶子 —— 叶节点具有相同的深度,叶节点指针为空
3. B树作为索引
-
提升性能 —— B树可以有效降低树的深度带来的I/O读写频繁的问题
-
数据data绑定在索引中,在查找数据时更方便
MySQL的索引不采用B树
4. 结构图
B+树🔍
1. 定义
是一颗多路平衡查找树🔍,非叶子节点只存储索引
MySQL等数据库的索引都采用B+树的数据结构来存储索引
2. 特点
- 存储量大 —— 非叶子节点不存储data,只存储索引(冗余)可以放置更多的索引
- 便于区间查找 —— 叶子节点间用双向链表结构,便于区间查找
- 有序性 —— 节点中的数据索引从左到右递增排列
- 唯一性 —— 所有索引元素不重复
- 叶子 —— 叶节点具有相同的深度,叶节点指针为空
3. 读数据步骤
例:查询key=30的数据
- 将根节点的数据从磁盘加载到内存 一次I/O
- 在内存中,用二分查找找到key位于下一个页的地址 二分查找
- 根据页地址,将下一个节点的数据从磁盘加载到内存 一次I/O
- 重复2,3
- 找到叶子节点,可以读取数据data
4. InnoDB的页大小
SHOW GLOBAL STATUS LIKE 'Innodb_page_size';
通过B+树存储数据,(假设数据项大小为1KB)可以存储1170*1170*16 个数据项
MySQL会将根节点的索引缓存在内存中,极大提高查询速率,通常查询只需要花费一次磁盘I/O的时间
5. 结构图
存储引擎
MyISAM
1. 定义
MyISAM是MySQL的默认数据库引擎(5.5版之前),索引文件和数据文件是分离的 【非聚集】
2. 组成
MyISAM数据表,皆由存储在硬盘上的3个文件所组成
文件命名:【数据表名称+不同扩展名】
- .frm--存储数据表定义
- .MYD--存放真正的数据
- .MYI--存储索引信息
4. 结构图
InnoDB
1. 定义
InnoDB,是MySQL的数据库引擎之一,现为MySQL的默认存储引擎
2. 组成
InnoDB数据表,皆由存储在硬盘上的2个文件所组成
文件命名:【数据表名称+不同扩展名】
- .frm--存储数据表定义
- .ibd--存储数据和索引
4. 特点
- B+Tree —— 数据表文件是按照B+Tree组织的索引结构文件
- 叶节点 —— 叶子节点包含完整的数据记录
- 主键索引 —— 表必须建主键
- 非主键索引 —— 非主键索引结构叶子节点存储的是主键值 【一致性】
5. 结构图
索引分类
聚集索引
-
定义
其索引树的叶子节点中存的是整行数据,表中行的物理顺序与键值的逻辑(索引)顺序相同。【通过双向链表来实现】一个表只能包含一个聚集索引。因为索引(目录)只能按照一种方法进行排序。
新华字典,聚集索引就像是拼音目录
-
查数据
聚集索引通过key查找查找到具体数据项
非聚集索引
-
定义
因为索引文件和数据文件是分离的,索引的逻辑顺序与磁盘上的物理存储顺序不同
非聚簇索引(普通索引)的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index)。
非聚集索引就像新华字典的偏旁字典,他结构顺序与实际存放顺序不一定一致
- 查数据
- 非聚集索引先通过key来查询到记录主键的值
- 根据记录主键的值来查询具体数据项【回表】
联合索引
1. 定义
联合索引即是由多个字段组成的一条索引。
2. 联合索引怎么使用?
根据最左前缀原理来使用
索引最左前缀原理
1. 定义
走联合索引时,条件要从左到右依次满足,不可缺少
2. 例子
建立联合索引
idx_a_b_c
(a
,b
,c
) USING BTREE
-
SQL 一
select * from test where a = '333' and b = '333' and c = '333';
走联合索引,因为有bc存在的情况下,a存在
-
SQL 二
select * from test where b = '333' and c = '333';
不会走联合索引,因为bc存在的情况下,a不存在
-
SQL 三
select * from test where a = '333' and b = '333';
走联合索引,因为b存在的情况下,a存在
3. 总结
所谓最左前缀原理,就是where条件下必须有联合索引的第一个字段,否则不会走联合索引。
问题
Q:为什么要使用索引?
-
数据随机存储 —— 表中的记录是随机存储在磁盘中,不一定是连续的,读取数据,要和磁盘做一次I/O交互
-
快速定位数据 —— 根据索引,可以不通过全表扫描,快速定位到数据
Q:B树和B+树区别?
- 性能 —— B+树在磁盘I/O的时候,不需要加载数据项,只需要加载索引项;而B树需要加载数据和索引,B+树性能更好
- 区间查找 —— 当需要区间查找时,B+树可以根据叶子节点的双向链表结构来进行查找,比B树性能更好
Q:为什么InnoDB表建议建立主键,并且推荐整型的自增主键?
-
主键
- InnoDB的ibd文件需要通过主键来建立B+树的索引结构
- 如果没有主键,InnoDB会扫描每一列并选取一个
not null
且unique
列来作为索引 - 如果找到符合要求的列,则默认生成一个内置6字节长的ROWID列来作为索引
-
自增主键
- 使用自增主键
- 每次插入新的记录时,记录就会顺序添加到当前索引节点的后续位置,主键的顺序按照数据记录的插入顺序排列,自动有序。当一页写满,就会自动开辟一个新的页
- 使用非自增主键
- 每次插入主键的值近似于随机,因此每次新纪录都要被插到现有索引页的中间某个位置,为了将新记录插到合适位置而移动数据,甚至目标页面可能已经被回写到磁盘上而从缓存中清掉,此时又要从磁盘上读回来,这增加了很多开销,同时频繁的移动、分页操作造成了大量的碎片,得到不够紧凑的索引结构,后续不得不通过OPTIMIZE TABLE来重建表并优化填充页面。
- 使用自增主键
Q:为什么非主键索引结构叶子节点存储的是主键值?
非主键索引结构是二级索引
- 节省存储空间 —— InnoDB数据本身已经在主键索引的B+树上,二级索引不需要再保存一份数据,节省空间。
- 一致性 —— 当数据需要更新时,只需要修改聚集索引,不需要重构二级索引,不需要维护多份数据。
Q:为什么联合索引要遵循最左前缀原理?
因为联合索引的数据结构仍然是B+树结构来组织的,索引维护的是以第一个字段来优先排序,当查询条件没有第一个字段就没有办法通过索引来比较定位数据
当没有第一个字段时,第二个字段走联合索引会导致无法排好序,因为第二个字段有序是基于第一个字段相等的一个局部的有序。后面字段同理