序言
涉浅水者得鱼虾,入深海者获蛟龙。
磁盘存储
我们需要知道数据库中的每一行的记录存储在磁盘中并不是连续存储的。
磁盘页
页是InnoDB存储引擎磁盘管理的最小单位,每个页默认16KB。可通过语句查看大小
SHOW GLOBAL STATUS like 'Innodb_page_size'
什么是索引?
答:索引是排好序的数据结构。
索引的数据结构有哪些?
-
二叉树
-
示例
-
特点
1.顺序性,根节点左边的都小于根节点以及根节点右侧节点(左边小于右边)
-
弊端
1.当数据规律是递增时,那么二叉树结构会线程线性列表,查找效率会低下
2.输的高度不可控,导致磁盘io读写性能低下
-
B树
示例
![](https://img-blog.csdnimg.cn/64a07658dbd5408892ab05f6b5bd339b.png)
特点
- 有序性,从左到右依次递增
- 叶子节点具有相同的深度,且指针为空
- 元素不重复
- 同一个高度,一个磁盘位置空间包含多个节点,且每个节点都包含完整数据。(相对二叉树来说,根几点只有一个节点,而B数以及B+数存在多个节点)
弊端
- 每个节点都包含该行(数据表层面)完整记录,导致每一层高度的磁盘页存储的节点数减少,从而导致相对B+树来说,高度增加。
举栗:上面我们说了一个磁盘页占用16k,如果一个数据节点占用1K,那么一个磁盘页最多放16个数据节点。相对来说,如果没有存放data,替换成字段类型占用大小(几B),是不是就能存储更多节点数据了。 - 叶子节点没有指针相互连接,从而不利于范围查找。
-
B+树
示例
特点
- 有序性,从左到右依次递增
- 非叶子节点不存储数据,只存储索引(冗余),为了存更多索引
举栗:依旧以上面默认磁盘页16K作为参考。假如1个BigInt占用8B,一个指针占用6B,则一个BigInt的数据在磁盘上大约整体占用14个字节,那么一个磁盘页大约存储 16K/14B,大约1170个索引;数据节点依旧按照1K来统计,也就16个索引。所以高度为3的磁盘页,大约存储
1170*1170*16=21902400(千万级条) - 区间访问,叶子节点之间有指针互相连接。可以范围查询
- 一般情况第一磁盘页的索引会提前加载到内存,内存中查找某个数值,速度极快,主要消耗在二级、三级...磁盘页上数据查找的磁盘io消耗
弊端
暂无。
注:
- 二级索引结构,叶子节点存储的不是该行所有data数据,而是主键的磁盘位置(1.为了节省空间;2.为了一致性,插入数据时主键索引先创建,二级索引回头只需要更新主键磁盘位置)
-
红黑树
示例
特点
- 二叉树特质,左边数小于右边数
- 自平衡,在插入过程中会自己平衡左右数值并进行旋转
- 根节点是黑色;节点是红色或者是黑色;从任一节点到它的每个叶子的所有路径都包含相同数目的黑色节点;所有的叶子都是黑色(叶子是NUIL节点);每个红色节点的两个子节点都是黑色,从每个叶子到根的所有路径上不可以有两个连续的红色节点;
弊端
- 只要是二叉树性质的(1个节点最多挂2个节点的)均面临树的高度问题
- 平衡旋转过程会导致效率低下
-
Hash表
示例
特点
- 对索引key进行hash,就可以定位位置
- 对于“=”以及“IN”查询效率高效,但是不支持范围查询
- 存在hash冲突问题
弊端
优点既是缺点。
数据表引擎详解
目前数据库建表时常用的两种引擎,如图:
聚簇索引
通过主键所在的叶子节点就可获得当前行所有记录,即为聚簇索引。
非聚簇索引
通过主键所在叶子节点只能获取到当前行所有数据在磁盘文件的地址,需要二次查找才能得到当前行所有数据。
最左匹配原则
假如现在我们有一张数据表,包含了name,age,addr等字段,并为该三个字段依序设定联合主键。
select * from student where name='niu'; -- 走索引
select * from student where age=28 and addr='北京'; --没有走索引
select * from student where addr='北京'; -- 没有走索引
最左匹配,为什么左边的字段列没有出现,我们就不走索引了?
我们依旧以上图为例,假如只查询age=30的记录。
按照我们上面说的索引应该是排好序的数据结构,可是当失去了最左边字段后,age字段只有在name相同的时候才是有序的;那么此时问题就来了,如果没有name字段相同,查age=30的,我们只能一个节点一个节点查找才能让记录匹配条件,因此也就失去了索引效果。
数据库为什么要设置主键
- Mysql 没有创建主键索引时,会从第1列查找所有数据不相等的列,如果所有列都不满足,Mysql会创建伪列rowid。代表主键(我们没必要将此小事交给数据库来做)
- 我们可以更快的定位并获取到一行记录
这里我们再介绍一下,为什么数据库建议设置自增int类型主键?
答:由于B+树的性质可得,当插入一个中间状态值的时候,需要分裂并移动其它数据节点,这样会降低效率;另外int相比字符串主键更节省空间;
为什么现在很多数据表用UUID做主键?
答:1.UUID可以理解成不会重复的,但是int类型的主键在分布式环境中可能会重复。