Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[修改]:修改 mysql 索引详解,修改聚集索引与非聚集索引图片,添加联合索引,最左前缀匹配原则,索引下推的概念 #1648

Merged
merged 2 commits into from
Apr 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions docs/database/mysql/mysql-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ tag:

## 索引的底层数据结构

### Hash表 & B+树
### Hash表

哈希表是键值对的集合,通过键(key)即可快速取出对应的值(value),因此哈希表可以快速检索数据(接近 O(1))。

Expand Down Expand Up @@ -76,8 +76,6 @@ B 树也称 B-树,全称为 **多路平衡查找树** ,B+ 树是 B 树的一
- B 树的叶子节点都是独立的;B+树的叶子节点有一条引用链指向与它相邻的叶子节点。
- B 树的检索的过程相当于对范围内的每个节点的关键字做二分查找,可能还没有到达叶子节点,检索就结束了。而 B+树的检索效率就很稳定了,任何查找都是从根节点到叶子节点的过程,叶子节点的顺序检索很明显。

![](https://img-blog.csdnimg.cn/20210420165409106.png)

在 MySQL 中,MyISAM 引擎和 InnoDB 引擎都是使用 B+Tree 作为索引结构,但是,两者的实现方式不太一样。(下面的内容整理自《Java 工程师修炼之道》)

MyISAM 引擎中,B+Tree 叶节点的 data 域存放的是数据记录的地址。在索引检索的时候,首先按照 B+Tree 搜索算法搜索索引,如果指定的 Key 存在,则取出其 data 域的值,然后以 data 域的值为地址读取相应的数据记录。这被称为“非聚簇索引”。
Expand All @@ -94,6 +92,8 @@ InnoDB 引擎中,其数据文件本身就是索引文件。相比 MyISAM,索

在 MySQL 的 InnoDB 的表中,当没有显示的指定表的主键时,InnoDB 会自动先检查表中是否有唯一索引且不允许存在null值的字段,如果有,则选择该字段为默认的主键,否则 InnoDB 将会自动创建一个 6Byte 的自增主键。

![](http://101.43.132.98:98/images/cluster-index.png)

### 二级索引(辅助索引)

**二级索引又称为辅助索引,是因为二级索引的叶子节点存储的数据是主键。也就是说,通过二级索引,可以定位主键的位置。**
Expand All @@ -110,7 +110,7 @@ InnoDB 引擎中,其数据文件本身就是索引文件。相比 MyISAM,索

二级索引:

![](https://img-blog.csdnimg.cn/20210420165254215.png)
![](http://101.43.132.98:98/images/no-cluster-index.png)

## 聚集索引与非聚集索引

Expand Down Expand Up @@ -190,6 +190,20 @@ SELECT id FROM table WHERE id=1;
覆盖索引:
![](https://img-blog.csdnimg.cn/20210420165341868.png)

## 联合索引

使用表中的多个字段创建索引,就是 **联合索引**,也叫 **组合索引** 或 **复合索引**。

## 最左前缀匹配原则

最左前缀匹配原则指的是,在使用联合索引时,**MySQL** 会根据联合索引中的字段顺序,从左到右依次到查询条件中去匹配,如果查询条件中存在与联合索引中最左侧字段相匹配的字段,则就会使用该字段过滤一批数据,直至联合索引中全部字段匹配完成,或者在执行过程中遇到范围查询,如 **`>`**、**`<`**、**`between`** 和 **`以%开头的like查询`** 等条件,才会停止匹配。

所以,我们在使用联合索引时,可以将区分度高的字段放在最左边,这也可以过滤更多数据。

## 索引下推

索引下推是 **MySQL 5.6** 版本中提供的一项索引优化功能,可以在非聚簇索引遍历过程中,对索引中包含的字段先做判断,过滤掉不符合条件的记录,减少回表次数。

## 创建索引的注意事项

**1.选择合适的字段创建索引:**
Expand Down
21 changes: 15 additions & 6 deletions docs/database/mysql/transaction-isolation-level.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ tag:

----

| 隔离级别 | 脏读 | 不可重复读 | 幻影读 |
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
| :---: | :---: | :---:| :---: |
| READ-UNCOMMITTED | √ | √ | √ |
| READ-COMMITTED | × | √ | √ |
Expand Down Expand Up @@ -127,17 +127,26 @@ SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTE
<div align="center">
<img src="https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-33-2可重复读.jpg"/>
</div>
#### 幻读

#### 防止幻读(可重复读)
##### 演示幻读出现的情况

<div align="center">
<img src="https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-33防止幻读(使用可重复读).jpg"/>
</div>
![](http://101.43.132.98:98/images/phantom_read.png)

一个事务对数据库进行操作,这种操作的范围是数据库的全部行,然后第二个事务也在对这个数据库操作,这种操作可以是插入一行记录或删除一行记录,那么第一个是事务就会觉得自己出现了幻觉,怎么还有没有处理的记录呢? 或者 怎么多处理了一行记录呢?
sql 脚本1 在第一次查询工资为 500 的记录时只有一条,sql 脚本 2 插入了一条工资为 500 的记录,提交之后;sql 脚本 1 在同一个事务中再次使用当前读查询发现出现了两条工资为 500 的记录这种就是幻读。

幻读和不可重复读有些相似之处 ,但是不可重复读的重点是修改,幻读的重点在于新增或者删除。

##### 解决幻读的方法

解决幻读的方式有很多,但是它们的核心思想就是一个事务在操作某张表数据的时候,另外一个事务不允许新增或者删除这张表中的数据了。解决幻读的方式主要有以下几种:

1. 将事务隔离级别调整为 `SERIALIZABLE`
2. 在可重复读的事务级别下,给事务操作的这张表添加表锁
3. 在可重复读的事务级别下,给事务操作的这张表添加 `Next-Key Locks`

> 说明:`Next-Key Locks` 相当于 行锁 + 间隙锁

### 参考

- 《MySQL技术内幕:InnoDB存储引擎》
Expand Down