Skip to content

Commit e5831d8

Browse files
committed
fix: add missing blank lines before lists in 01_mysql_redis.md
1 parent bf832b3 commit e5831d8

1 file changed

Lines changed: 27 additions & 0 deletions

File tree

cpp_interview_notes/04_database_cache/01_mysql_redis.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,17 @@ MySQL 和 Redis 放在一起问,核心不是让你背两个产品的特性,
3333

3434
### 更深入的理解
3535
索引的本质不是"让查询 magically 变快",而是:
36+
3637
- 提前按某种规则组织数据访问路径
3738
- 让查询少扫很多不必要的数据页
3839

3940
如果没有索引,很多查询只能:
41+
4042
- 从头到尾一行一行看
4143
- 或扫描大量无关页
4244

4345
而有索引后,数据库可以:
46+
4447
- 快速定位起点
4548
- 顺着有序结构继续扫范围
4649
- 减少磁盘 / buffer pool 的无效访问
@@ -59,6 +62,7 @@ B+ 树适合磁盘/页式存储,层高低、磁盘 IO 次数少,叶子节点
5962
### 为什么不是红黑树?
6063

6164
红黑树是二叉结构,树高通常更高。对于数据库这种页式存储来说:
65+
6266
- 层高更高 → 访问路径更长
6367
- 磁盘/页 IO 次数更不友好
6468

@@ -67,21 +71,25 @@ B+ 树适合磁盘/页式存储,层高低、磁盘 IO 次数少,叶子节点
6771
### 为什么不是哈希?
6872

6973
哈希适合:
74+
7075
- 等值查询
7176

7277
但它不擅长:
78+
7379
- 范围查询
7480
- 排序
7581
- 最左匹配后的连续扫描
7682

7783
而数据库索引特别常见的需求恰恰是:
84+
7885
- `>``<``between`
7986
- `order by`
8087
- 范围过滤
8188

8289
### 为什么是 B+ 树,不是 B 树?
8390

8491
B+ 树通常:
92+
8593
- 非叶子节点只存键,不存整行数据
8694
- 单页能容纳更多索引项
8795
- 树更矮
@@ -98,12 +106,14 @@ B+ 树通常:
98106
### 标准回答
99107

100108
在 InnoDB 中:
109+
101110
- **聚簇索引**叶子节点直接存整行数据
102111
- **二级索引**叶子节点存主键值,需要再根据主键去聚簇索引拿整行
103112

104113
### 更深入地理解
105114

106115
这意味着:
116+
107117
- 表数据本身就是按主键组织的
108118
- 主键访问通常路径最短
109119
- 二级索引查全字段时,可能需要两跳
@@ -136,6 +146,7 @@ B+ 树通常:
136146
### 什么时候容易被追问?
137147

138148
当面试官问:
149+
139150
- 为什么某 SQL 走了索引还是慢?
140151
- explain 看起来用了 key,怎么性能还差?
141152

@@ -154,6 +165,7 @@ B+ 树通常:
154165
因为它减少了一次访问主表/聚簇索引的过程。
155166

156167
特别是在:
168+
157169
- 命中行较多
158170
- 查询非常频繁
159171
- 热路径 SQL
@@ -163,6 +175,7 @@ B+ 树通常:
163175
### 但不要走极端
164176

165177
不是所有查询都应该为了覆盖索引去疯狂加字段,否则会带来:
178+
166179
- 索引膨胀
167180
- 写入放大
168181
- 维护成本上升
@@ -226,11 +239,13 @@ B+ 树通常:
226239
### 不要机械背表格
227240

228241
更关键的是理解隔离级别是在权衡:
242+
229243
- 并发性能
230244
- 锁冲突
231245
- 一致性强度
232246

233247
隔离越强,通常:
248+
234249
- 并发越受限
235250
- 实现成本越高
236251
- 吞吐可能越低
@@ -250,15 +265,18 @@ B+ 树通常:
250265
### 为什么叫"幻"读?
251266

252267
因为不是原有某一行变了,而是:
268+
253269
- 范围里突然"冒出"了新的记录
254270

255271
这和不可重复读的区别在于:
272+
256273
- 不可重复读更像"同一行值变了"
257274
- 幻读更像"结果集成员变了"
258275

259276
### InnoDB 常见回答
260277

261278
InnoDB 在可重复读级别下会结合:
279+
262280
- MVCC
263281
- Next-Key Lock
264282

@@ -275,10 +293,12 @@ MVCC(多版本并发控制)通过保存数据多个版本,使读操作无
275293
### 它解决了什么问题?
276294

277295
如果所有读都和写互相强阻塞:
296+
278297
- 并发会很差
279298
- 热点表会很卡
280299

281300
MVCC 的核心思想是:
301+
282302
- 读不一定非要读"当前最新版"
283303
- 可以读一个对当前事务可见的历史版本
284304

@@ -302,6 +322,7 @@ MVCC 的核心思想是:
302322
### 更完整的理解
303323

304324
Redis 快不只是"因为在内存里",还因为它在工程上刻意追求:
325+
305326
- 数据路径短
306327
- 命令模型简单
307328
- 单线程避免复杂锁竞争
@@ -310,6 +331,7 @@ Redis 快不只是"因为在内存里",还因为它在工程上刻意追求:
310331
### 但也别神化
311332

312333
Redis 快并不意味着:
334+
313335
- 所有命令都永远快
314336
- 大 key / 大范围操作没问题
315337
- 单线程就没有阻塞风险
@@ -327,17 +349,20 @@ Redis 快并不意味着:
327349
### 更深入一点
328350

329351
Redis 选择单线程核心执行模型,本质是在做一个工程取舍:
352+
330353
- 放弃复杂共享内存并发
331354
- 换取实现简单、延迟稳定、锁开销低
332355

333356
### 这不代表 Redis "只有一个线程"
334357

335358
实际系统中还可能有:
359+
336360
- IO 线程
337361
- 后台持久化线程
338362
- 异步释放资源线程
339363

340364
但命令执行核心路径长期以来强调的是:
365+
341366
- 尽量串行
342367
- 尽量减少锁竞争
343368

@@ -361,6 +386,7 @@ Redis 选择单线程核心执行模型,本质是在做一个工程取舍:
361386
### 面试不要只背名字
362387

363388
更重要的是知道它们分别适合:
389+
364390
- String:缓存对象、计数器、分布式锁基础
365391
- Hash:对象字段聚合存储
366392
- Set:去重、共同好友、标签集合
@@ -500,6 +526,7 @@ Redis 选择单线程核心执行模型,本质是在做一个工程取舍:
500526
## 进阶建议
501527

502528
如果你想把这一章练到不怕追问,至少做到:
529+
503530
- 能说清 B+ 树为什么适合数据库
504531
- 能解释回表和覆盖索引的性能意义
505532
- 能讲清事务隔离级别的权衡

0 commit comments

Comments
 (0)