Skip to content

Commit

Permalink
db
Browse files Browse the repository at this point in the history
  • Loading branch information
deipss committed Feb 20, 2024
1 parent 6016c71 commit a7caad1
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 8 deletions.
19 changes: 19 additions & 0 deletions docs/Database/B+树.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,32 @@ nav_order: 8
---

# B+树

定义:
B+树是一种数据结构,是一个N叉排序树,每个节点通常有多个孩子,一棵B+树包含根节点、内部节点和叶子节点。
根节点可能是一个叶子节点, 也可能是一个包含两个或两个以上孩子节点的节点。

B+树通常用于数据库和操作系统的文件系统中。NTFS、ReiserFS、NSS、XFS、JFS、ReFS和BFS等文件系统都在使用B+树作为元数据索引。
B+树的特点是能够保持数据稳定有序, 其插入与修改拥有较稳定的对数时间复杂度。B+树元素自底向上插入。

![b+.png](img%2Fb%2B.png)

## 特点:

- 1 B+树包含2种类型的结点:内部结点(也称索引结点)和叶子结点。根结点本身即可以是内部结点,也可以是叶子结点。根结点的关键字个数最少可以只有1个。
- 2 m阶B+树表示了内部结点最多有m-1个关键字(或者说内部结点最多有m个子树),阶数m同时限制了叶子结点最多存储m-1个记录。
- 3 内部结点中的key都按照从小到大的顺序排列,对于内部结点中的一个key,左树中的所有key都小于它,右子树中的key都大于等于它。叶子结点中的记录也按照key的大小排列。
- 4 每个叶子结点都存有相邻叶子结点的指针,叶子结点本身依关键字的大小自小而大顺序链接。

## 为什么是B+树而不是B树呢

- B树每个节点中不仅包含数据的key值,还有data值。
而每一个页的存储空间是有限的,如果data数据较大时将会导致每个节点能存储的key的数量很小,
要保存同样多的key,就需要增加树的高度。树的高度每增加一层,查询时的磁盘I/O次数就增加一次,
进而影响查询效率。而在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,
而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降低B+树的高度。
- B+树的叶子节点上有指针进行相连,因此在做数据遍历的时候,
只需要对叶子节点进行遍历即可,这个特性使得B+树非常适合做范围查询。

# 参考文献

Expand Down
Binary file added docs/Database/img/b+.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/Database/img/combine_index.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/Database/img/innoDB_lock.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 52 additions & 6 deletions docs/Database/mysql.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@ parent: Database
nav_order: 1
---


# 1. 索引

## 1.1. 回表

指通过索引查询命中主键ID,再返回到表中去读取ID对应的列数据(这些列数据不在索引中)
## 1.1. 聚集索引与回表

### 1.1.1. 聚集索引 (clustered index)

InnoDB聚集索引的叶子节点存储行记录,因此, InnoDB必须要有且只有一个聚集索引。
聚集索引(clustered)也称聚簇索引,这种索引中,数据库表行中数据的物理顺序与键值的逻辑(索引)顺序相同。
一个表的物理顺序只有一种情况,因此对应的聚集索引只能有一个。如果某索引不是聚集索引,
则表中的行物理顺序与索引顺序不匹配,与非聚集索引相比,聚集索引有着更快的检索速度。

> 自增主键和uuid作为主键的区别么?由于主键使用了聚集索引,如果主键是自增id,
> 那么对应的数据一定也是相邻地存放在磁盘上的,写入性能比较高。
> 如果是uuid的形式,频繁的插入会使innodb频繁地移动磁盘块,写入性能就比较低了。
- 如果表定义了主键,则Primary Key 就是聚集索引;
- 如果表没有定义主键,则第一个非空唯一索引(Not NULL Unique)列是聚集索引;
Expand All @@ -23,9 +26,51 @@ InnoDB聚集索引的叶子节点存储行记录,因此, InnoDB必须要有
### 1.1.2. 普通索引(secondary index)

普通索引也叫二级索引,除聚簇索引外的索引都是普通索引,即非聚簇索引。
不同于聚集索引,非聚集索引叶子节点上不再是真实数据,而是存储了索引字段自身值和主键索引。
使用聚集索引查询可以直接定位到记录,而普通索引通常需要扫描两遍索引树(第一次普通索引,第二次聚集索引),
即先通过普通索引定位到主键值,在通过聚集索引定位到行记录,这就是所谓的回表查询,它的性能比扫描一遍索引树低。

- InnoDB的普通索引叶子节点存储的是主键(聚簇索引)的值,而MyISAM的普通索引存储的是记录指针。

### 1.1.3. 回表

回表或者二次查询:使用聚集索引查询可以直接定位到记录,
而普通索引通常需要扫描两遍索引树,即先通过普通索引定位到主键值,
在通过聚集索引定位到行记录,这就是所谓的回表查询,它的性能比扫描一遍索引树低

## 1.2. 组合索引

- https://zhuanlan.zhihu.com/p/346849749

![combine_index.png](img%2Fcombine_index.png)

### 1.2.1. 等值最左前缀匹配

- 1、全值匹配查询时(where子句搜索条件顺序调换不影响索引使用,因为查询优化器会自动优化查询顺序 ),可以用到联合索引
- 2、匹配左边的列时,可以用到联合索引
- 3、未从最左列开始时,无法用到联合索引
- 4、查询列不连续时,无法使用联合索引(会用到a列索引,但c排序依赖于b,所以会先通过a列的索引筛选出a=1的记录,
再在这些记录中遍历筛选c=3的值,是一种不完全使用索引的情况)

### 1.2.2. 范围最左前缀匹配

- 1 范围查询最左列,可以使用联合索引
- 2 精确匹配最左列并范围匹配其右一列(a值确定时,b是有序的,因此可以使用联合索引)
- 3 精确匹配最左列并范围匹配非右一列(a值确定时,c排序依赖b,因此无法使用联合索引,
但会使用a列索引筛选出a>2的记录行,再在这些行中条件 c >3逐条过滤)

## 1.3. 索引失效

- 条件字段原因
- <>、NOT、in、not exists
- 查询条件中使用OR
- 查询条件使用LIKE通配符 SQL语句中,使用后置通配符会走索引,
例如查询姓张的学生(SELECT * FROM student WHERE name LIKE '张%'),
而前置通配符(SELECT * FROM student WHERE name LIKE '%东')会导致索引失效而进行全表扫描。
- 索引列上做操作(计算,函数,(自动或者手动)类型装换)
- 索引列数据类型不匹配 SELECT * FROM student WHERE age=’18‘索引失效,因为age是整形
- 索引列使用IS NOT NULL或者IS NULL可能会导致无法使用索引

# 2. explain

`EXPLAIN` 是 MySQL 中用于分析查询执行计划的命令。当你对一个 SQL 查询使用 `EXPLAIN` 时,MySQL
Expand Down Expand Up @@ -58,7 +103,8 @@ WHERE age > 25;
* **id**: 查询的标识符。
* **select_type**: 查询的类型(例如 SIMPLE, SUBQUERY, DERIVED 等)。
* **table**: 输出的表名。
* **type**: 访问类型(例如 ALL, index, range, ref, eq_ref, const, system, NULL)。https://www.cnblogs.com/xxoome/p/14434061.html
* **type**: 访问类型(例如 ALL, index, range, ref, eq_ref, const, system,
NULL)。https://www.cnblogs.com/xxoome/p/14434061.html
* **possible_keys**: 可能使用的索引。
* **key**: 实际使用的索引。
* **key_len**: 使用的索引的长度。
Expand Down
21 changes: 21 additions & 0 deletions docs/Database/mysql锁与事务.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
layout: default
title: mysql锁与事务
parent: Database
nav_order: 1
---

#

## 锁的分类

行锁
表锁(InnoDB中,意向锁即表级别的锁)

![img.png](img/innoDB_lock.png)

## 锁的算法

- 行锁:单行记录上锁
- 间隙锁:锁定一个范围,但不包括本身
- Next-Key锁=行锁+间隙锁(为了应对幻读的问题)
19 changes: 17 additions & 2 deletions docs/spring/事务.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ parent: Spring
3. 幻读:事务A在执行读取操作,需要两次统计数据的总量,前一次查询数据总量后,此时事务B执行了新增数据的操作并提交后,
这个时候事务A读取的数据总量和之前统计的不一样,就像产生了幻觉一样,平白无故的多了几条数据,成为幻读。

> 不可重复读和幻读的区别是,前者是update,后者是insert
> 不可重复读和幻读的区别是,前者是update、delete,后者是insert
# 3. 事务的隔离级别

Mysql中,默认的事务隔离级别是**可重复读(repeatable-read)**,为了解决不可重复读,Innodb采用了MVCC(多版本并发控制)来解决这一问题。
MVCC是利用在每条数据后面加了隐藏的两列(创建版本号和删除版本号),每个事务在开始的时候都会有一个递增的版本号,
用来和查询到的每行记录的版本号进行比较。
MYSQL MVCC


| 事务级别 | 脏读 | 不可重复读 | 幻读 |
|-----------------------|----|-------|----|
Expand All @@ -37,6 +37,21 @@ MYSQL MVCC
| 读提交 Read committed | N | Y | Y |
| 读未提交 Read uncommitted | Y | Y | Y |

## MVCC

在InnoDB中,会在每行数据后添加两个额外的隐藏的值来实现MVCC,这两个值一个记录这行数据何时被创建,另外一个记录这行数据何时过期(或者被删除)。
在实际操作中,存储的并不是时间,而是事务的版本号,每开启一个新事务,事务的版本号就会递增。 在可重读Repeatable reads事务隔离级别下:

- SELECT时,读取创建版本号<=当前事务版本号,删除版本号为空或>当前事务版本号。
- INSERT时,保存当前事务版本号为行的创建版本号
- DELETE时,保存当前事务版本号为行的删除版本号
- UPDATE时,插入一条新纪录,保存当前事务版本号为行创建版本号,同时保存当前事务版本号到原来删除的行

通过MVCC,虽然每行记录都需要额外的存储空间,更多的行检查工作以及一些额外的维护工作,但可以减少锁的使用,
大多数读操作都不用加锁,读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行,也只锁住必要行。



# 4. 事务的传播性

## 4.1. 什么时候出现事务的传播
Expand Down

0 comments on commit a7caad1

Please sign in to comment.