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

Redis重要知识点部分勘误 #2629

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
26 changes: 13 additions & 13 deletions docs/database/mysql/mysql-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ tag:

索引的作用就相当于书的目录。打个比方:我们在查字典的时候,如果没有目录,那我们就只能一页一页地去找我们需要查的那个字,速度很慢;如果有目录了,我们只需要先去目录里查找字的位置,然后直接翻到那一页就行了。

索引底层数据结构存在很多种类型,常见的索引结构有:B 树、 B+ 树 和 Hash、红黑树。在 MySQL 中,无论是 Innodb 还是 MyISAM,都使用了 B+ 树作为索引结构。
索引底层数据结构存在很多种类型,常见的索引结构有:B树、 B+树 和 Hash、红黑树。在 MySQL 中,无论是 Innodb 还是 MyISAM,都使用了 B+树作为索引结构。

## 索引的优缺点

Expand Down Expand Up @@ -112,20 +112,20 @@ AVL 树采用了旋转操作来保持平衡。主要有四种旋转操作:LL

**红黑树的应用还是比较广泛的,TreeMap、TreeSet 以及 JDK1.8 的 HashMap 底层都用到了红黑树。对于数据在内存中的这种情况来说,红黑树的表现是非常优异的。**

### B 树& B+
### B树& B+树

B 树也称 B- 树,全称为 **多路平衡查找树**,B+ 树是 B 树的一种变体。B 树和 B+ 树中的 B 是 `Balanced`(平衡)的意思。
B树也称 B-树,全称为 **多路平衡查找树**,B+树是 B树的一种变体。B树和 B+树中的 B 是 `Balanced`(平衡)的意思。

目前大部分数据库系统及文件系统都采用 B-Tree 或其变种 B+Tree 作为索引结构。

**B 树& B+ 树两者有何异同呢?**
**B树& B+树两者有何异同呢?**

- B 树的所有节点既存放键(key)也存放数据(data),而 B+ 树只有叶子节点存放 key 和 data,其他内节点只存放 key。
- B 树的叶子节点都是独立的;B+ 树的叶子节点有一条引用链指向与它相邻的叶子节点。
- B 树的检索的过程相当于对范围内的每个节点的关键字做二分查找,可能还没有到达叶子节点,检索就结束了。而 B+ 树的检索效率就很稳定了,任何查找都是从根节点到叶子节点的过程,叶子节点的顺序检索很明显。
- 在 B 树中进行范围查询时,首先找到要查找的下限,然后对 B 树进行中序遍历,直到找到查找的上限;而 B+ 树的范围查询,只需要对链表进行遍历即可。
- B树的所有节点既存放键(key也存放数据data,而 B+树只有叶子节点存放 key 和 data,其他内节点只存放 key。
- B树的叶子节点都是独立的;B+树的叶子节点有一条引用链指向与它相邻的叶子节点。
- B树的检索的过程相当于对范围内的每个节点的关键字做二分查找,可能还没有到达叶子节点,检索就结束了。而 B+树的检索效率就很稳定了,任何查找都是从根节点到叶子节点的过程,叶子节点的顺序检索很明显。
- 在 B树中进行范围查询时,首先找到要查找的下限,然后对 B树进行中序遍历,直到找到查找的上限;而 B+树的范围查询,只需要对链表进行遍历即可。

综上,B+ 树与 B 树相比,具备更少的 IO 次数、更稳定的查询效率和更适于范围查询这些优势。
综上,B+树与 B树相比,具备更少的 IO 次数、更稳定的查询效率和更适于范围查询这些优势。

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

Expand Down Expand Up @@ -198,18 +198,18 @@ PS:不懂的同学可以暂存疑,慢慢往下看,后面会有答案的,

聚簇索引(Clustered Index)即索引结构和数据一起存放的索引,并不是一种单独的索引类型。InnoDB 中的主键索引就属于聚簇索引。

在 MySQL 中,InnoDB 引擎的表的 `.ibd`文件就包含了该表的索引和数据,对于 InnoDB 引擎表来说,该表的索引(B+ 树)的每个非叶子节点存储索引,叶子节点存储索引和索引对应的数据。
在 MySQL 中,InnoDB 引擎的表的 `.ibd`文件就包含了该表的索引和数据,对于 InnoDB 引擎表来说,该表的索引(B+树)的每个非叶子节点存储索引,叶子节点存储索引和索引对应的数据。

#### 聚簇索引的优缺点

**优点**:

- **查询速度非常快**:聚簇索引的查询速度非常的快,因为整个 B+ 树本身就是一颗多叉平衡树,叶子节点也都是有序的,定位到索引的节点,就相当于定位到了数据。相比于非聚簇索引, 聚簇索引少了一次读取数据的 IO 操作。
- **查询速度非常快**:聚簇索引的查询速度非常的快,因为整个 B+树本身就是一颗多叉平衡树,叶子节点也都是有序的,定位到索引的节点,就相当于定位到了数据。相比于非聚簇索引, 聚簇索引少了一次读取数据的 IO 操作。
- **对排序查找和范围查找优化**:聚簇索引对于主键的排序查找和范围查找速度非常快。

**缺点**:

- **依赖于有序的数据**:因为 B+ 树是多路平衡树,如果索引的数据不是有序的,那么就需要在插入时排序,如果数据是整型还好,否则类似于字符串或 UUID 这种又长又难比较的数据,插入或查找的速度肯定比较慢。
- **依赖于有序的数据**:因为 B+树是多路平衡树,如果索引的数据不是有序的,那么就需要在插入时排序,如果数据是整型还好,否则类似于字符串或 UUID 这种又长又难比较的数据,插入或查找的速度肯定比较慢。
- **更新代价大**:如果对索引列的数据被修改时,那么对应的索引也将会被修改,而且聚簇索引的叶子节点还存放着数据,修改代价肯定是较大的,所以对于主键索引来说,主键一般都是不可被修改的。

### 非聚簇索引(非聚集索引)
Expand Down Expand Up @@ -478,7 +478,7 @@ MySQL 可以简单分为 Server 层和存储引擎层这两层。Server 层处

### 尽可能的考虑建立联合索引而不是单列索引

因为索引是需要占用磁盘空间的,可以简单理解为每个索引都对应着一颗 B+ 树。如果一个表的字段过多,索引过多,那么当这个表的数据达到一个体量后,索引占用的空间也是很多的,且修改索引时,耗费的时间也是较多的。如果是联合索引,多个字段在一个索引上,那么将会节约很大磁盘空间,且修改数据的操作效率也会提升。
因为索引是需要占用磁盘空间的,可以简单理解为每个索引都对应着一颗 B+树。如果一个表的字段过多,索引过多,那么当这个表的数据达到一个体量后,索引占用的空间也是很多的,且修改索引时,耗费的时间也是较多的。如果是联合索引,多个字段在一个索引上,那么将会节约很大磁盘空间,且修改数据的操作效率也会提升。

### 注意避免冗余索引

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ tag:

在我看来,造成这个问题的原因是我们在学习 Redis 的时候,可能只是简单写了一些 Demo,并没有去关注缓存的读写策略,或者说压根不知道这回事。

但是,搞懂 3 种常见的缓存读写策略对于实际工作中使用缓存以及面试中被问到缓存都是非常有帮助的
但是,搞懂 3 种常见的缓存读写策略,对于实际工作中使用缓存以及面试中被问到缓存都是非常有帮助的

**下面介绍到的三种模式各有优劣,不存在最佳模式,根据具体的业务场景选择适合自己的缓存读写模式。**

Expand All @@ -23,17 +23,17 @@ Cache Aside Pattern 中服务端需要同时维系 db 和 cache,并且是以 d

**写**:

- 先更新 db
- 然后直接删除 cache
- 先更新 db
- 然后直接删除 cache。

简单画了一张图帮助大家理解写的步骤。

![](https://oss.javaguide.cn/github/javaguide/database/redis/cache-aside-write.png)

**读** :
**读**

- 从 cache 中读取数据,读取到就直接返回
- cache 中读取不到的话,就从 db 中读取数据返回
- 从 cache 中读取数据,读取到就直接返回
- cache 中读取不到的话,就从 db 中读取数据返回
- 再把数据放到 cache 中。

简单画了一张图帮助大家理解读的步骤。
Expand All @@ -42,9 +42,9 @@ Cache Aside Pattern 中服务端需要同时维系 db 和 cache,并且是以 d

你仅仅了解了上面这些内容的话是远远不够的,我们还要搞懂其中的原理。

比如说面试官很可能会追问:“**在写数据的过程中,可以先删除 cache ,后更新 db 么?**”
比如说面试官很可能会追问:“**在写数据的过程中,可以先删除 cache,后更新 db 么?**”

**答案:** 那肯定是不行的!因为这样可能会造成 **数据库(db)和缓存(Cache)数据不一致**的问题。
**答案**:那肯定是不行的!因为这样可能会造成 **数据库(db)和缓存(Cache)数据不一致** 的问题。

举例:请求 1 先写数据 A,请求 2 随后读数据 A 的话,就很有可能产生数据不一致性的问题。

Expand All @@ -54,7 +54,7 @@ Cache Aside Pattern 中服务端需要同时维系 db 和 cache,并且是以 d

当你这样回答之后,面试官可能会紧接着就追问:“**在写数据的过程中,先更新 db,后删除 cache 就没有问题了么?**”

**答案:** 理论上来说还是可能会出现数据不一致性的问题,不过概率非常小,因为缓存的写入速度是比数据库的写入速度快很多。
**答案**:理论上来说还是可能会出现数据不一致性的问题,不过概率非常小,因为缓存的写入速度是比数据库的写入速度快很多。

举例:请求 1 先读数据 A,请求 2 随后写数据 A,并且数据 A 在请求 1 请求之前不在缓存中的话,也有可能产生数据不一致性的问题。

Expand All @@ -64,11 +64,11 @@ Cache Aside Pattern 中服务端需要同时维系 db 和 cache,并且是以 d

现在我们再来分析一下 **Cache Aside Pattern 的缺陷**。

**缺陷 1:首次请求数据一定不在 cache 的问题**
**缺陷 1:首次请求数据一定不在 cache 的问题**

解决办法:可以将热点数据可以提前放入 cache 中。

**缺陷 2:写操作比较频繁的话导致 cache 中的数据会被频繁被删除,这样会影响缓存命中率 。**
**缺陷 2:写操作比较频繁的话导致 cache 中的数据会被频繁被删除,这样会影响缓存命中率。**

解决办法:

Expand All @@ -81,7 +81,7 @@ Read/Write Through Pattern 中服务端把 cache 视为主要数据存储,从

这种缓存读写策略小伙伴们应该也发现了在平时在开发过程中非常少见。抛去性能方面的影响,大概率是因为我们经常使用的分布式缓存 Redis 并没有提供 cache 将数据写入 db 的功能。

**写(Write Through):**
**写(Write Through)**:

- 先查 cache,cache 中不存在,直接更新 db。
- cache 中存在,则先更新 cache,然后 cache 服务自己更新 db(**同步更新 cache 和 db**)。
Expand All @@ -90,9 +90,9 @@ Read/Write Through Pattern 中服务端把 cache 视为主要数据存储,从

![](https://oss.javaguide.cn/github/javaguide/database/redis/write-through.png)

**读(Read Through):**
**读(Read Through)**:

- 从 cache 中读取数据,读取到就直接返回
- 从 cache 中读取数据,读取到就直接返回。
- 读取不到的话,先从 db 加载,写入到 cache 后返回响应。

简单画了一张图帮助大家理解读的步骤。
Expand Down
Loading