目录
Day 1:SQL基础
1. 什么是SQL?(Structured Query Language)
2. SQL语句有哪些分类?
🍉区分:
🍉为什么update/delete一定要加where?
3. 增删改查(CRUD)
🍉什么是CRUD?
4. SELECT查询执行顺序(重点)
5. Where和Having区别(面试常问)
6. GROUP BY是什么?⭐⭐⭐
7. JOIN是什么?⭐⭐⭐⭐
Day 2:MySQL索引 ⭐
1. 什么是索引?(必背)
2. 为什么需要索引?
3. 索引的底层结构是什么?⭐⭐⭐⭐
🍉为什么使用B+Tree?
4. 为什么不用二叉树?为什么不用Hash索引?⭐⭐⭐⭐
5. B+Tree是什么?⭐⭐⭐⭐⭐
6. 索引的优缺点 ⭐⭐⭐⭐
7. 什么字段适合建立索引?⭐⭐⭐⭐
🍉什么字段不适合?
8、为什么B+Tree特别适合范围查询?
9、那B+Tree和B树相比,有什么区别?为什么数据库更喜欢B+Tree?
Day 3:MySQL 索引进阶 🔥
1. 什么是聚簇索引?🔥🔥🔥
2. 什么是二级索引?🔥🔥🔥
3. 什么是回表?什么是覆盖索引?🔥🔥🔥(高频)
4. 什么是联合索引?什么是最左匹配原则?🔥🔥🔥🔥
5. 哪些情况可能导致索引失效?🔥🔥🔥🔥(高频)
6. 为什么不建议 select * ?🔥🔥
7、为什么①通常可以正常利用索引,而②对索引列使用函数后可能无法正常利用这个索引?
Day 4:MySQL 事务篇 🧩
1. 什么是事务?💎为什么需要事务?🔷
3. 事务MySQL中怎么使用?🔷
4. 什么是 ACID?💎💎
5. 并发事务会出现什么问题?💎💎
① 脏读 💎
②不可重复读 💎
③幻读 💎
6. MySQL事务隔离级别 💎💎
7. MySQL InnoDB 默认隔离级别 💎💎
8. 四种隔离级别解决什么问题?💎
Day 5:MVCC + MySQL 锁 🛡️
1、什么是 MVCC?🔥🔥🔥
2 、为什么需要 MVCC?🔥🔥🔥
3、undo log的两大作用:
4、Read View
🍉为什么 InnoDB 的 Repeatable Read(可重复读)能够解决不可重复读问题?请从undo log、MVCC、版本链和 Read View 的角度解释。
5、什么是快照读和当前读?🔥🔥🔥
6、什么是共享锁和排他锁?
表锁 vs 行锁
记录锁(Record Lock)vs 间隙锁(Gap Lock)
为啥(临键锁) Next-Key Lock 能帮助防止幻读?🔥🔥🔥🔥
7、InnoDB 在 RR 隔离级别下,是怎么处理幻读问题的?
8、为什么说 InnoDB 的查询条件如果没有合适的索引,可能导致“锁范围扩大”,甚至表现得像锁表?
🍉什么情况下行锁可能退化成类似“锁表”的效果?
🍉快照读 && 当前读
9、为什么 SELECT ... FOR UPDATE 不能像普通 SELECT 一样只读取历史快照,而要读取当前最新的数据并加锁?
🍉事务 A COMMIT 之后,事务 B 会发生什么?
🍉如果事务 A 还是持有 X Lock,但事务 B 执行select
事务 B 会不会被阻塞?为什么?
Day6:SQL 优化与 EXPLAIN 🔥🔥🔥🔥
第一题 🔥🔥🔥:什么是慢 SQL?
第二题 🔥🔥🔥🔥:EXPLAIN 是干什么的?
第三题 🔥🔥🔥🔥:
为什么不能看到 key != NULL、SQL 使用了索引,就直接判断“这条 SQL 性能很好”?
为什么 Extra = Using index 通常是一个比较好的信号?
第四题:SQL优化---深分页
Day7:InnoDB 底层 + MySQL 日志体系
1、什么是 Buffer Pool?InnoDB 为什么需要 Buffer Pool?
2、是不是每执行一次 UPDATE,MySQL 都要立刻把修改后的数据写回磁盘?
3、既然有了 redo log,为什么还需要 binlog?redo log 和 binlog 有什么区别?
4、为什么 MySQL 需要两阶段提交?
5、redo log 为什么叫“循环写”? binlog叫“追加写”?
6、一个update的背后流程图
Day 1:SQL基础
1. 什么是SQL?(Structured Query Language)
回答:
是一种用于操作关系型数据库的语言。
主要用于对数据库中的数据进行:
定义、操作、查询、控制。
比如:
MySQL、Oracle(/ˈɔːrəkəl/)、PostgreSQL(波斯格瑞) 等关系型数据库都支持SQL
2. SQL语句有哪些分类?
MySQL中常见分为:
① DDL(Data Definition Language)
是数据定义语言,主要用来 定义数据库对象结构
比如数据库、表、字段等
常见操作包括create、alter、drop、truncate。
create用于创建数据库对象,比如创建表
alter用于修改数据库对象结构,如增加字段、修改字段类型、删除字段等。
🍉区分:
drop:删除整个表对象,表结构和数据都会被删除。
truncate:清空表中的所有数据,但是保留表的结构和字段,之后仍然可以继续使用这个表。
② DML(Data Manipulation Language)
是数据操作语言,主要用于操作表中的数据
包括:insert、update、delete
🍉为什么update/delete一定要加where?
update和delete加where条件是为了指定操作的数据范围。如果不加where条件,会默认操作整张表的数据,可能导致大量数据被错误修改或删除
③ DQL(Data Query Language)
是数据查询语言,最常用的命令是select
用于 查询指定字段、筛选数据以及 进行排序、分组统计等操作
④ DCL(Data Control Language)
是数据控制语言。主要用于管理数据库用户的权限,
常见命令有 grant用于授权,revoke用于撤销权限
3. 增删改查(CRUD)
英文 | 中文 | SQL |
|---|---|---|
Create | 创建 | INSERT |
Read | 读取 | SELECT |
Update | 更新 | UPDATE |
Delete | 删除 | DELETE |
🍉什么是CRUD?
CRUD是数据库中最基本的数据操作,包括创建、查询、修改、删除,
对应SQL中的 insert、select、update、delete。
4. SELECT查询执行顺序(重点)
先找表(from),再过滤(where),再分组(group by),
再过滤组(having),再选字段(select),
再排序(order by),再分页(limit)
select name, count(*) -- 选择最终要返回的字段,并使用count(*)统计数量 from user -- 从user表中获取数据(确定数据来源) where age > 18 -- 过滤原始数据,只保留年龄大于18的数据 group by name -- 根据name字段进行分组 having count(*) > 5 -- 对分组后的结果进行过滤,只保留数量大于5的组 order by count(*) desc -- 按统计数量进行降序排序(从大到小) limit 10; -- 最后只返回10条数据(分页)5. Where和Having区别(面试常问)
where 和 having都是用于过滤数据,区别在于
where过滤的是原始数据,在group by之前执行
having过滤的是分组后的结果,在group by之后执行。
where不能使用聚合函数,而having可以结合count、max、min等聚合函数。
6. GROUP BY是什么?⭐⭐⭐
对查询结果进行分组统计
例如:
统计每个城市用户数量。
user表:
| name | city |
|---|---|
| 张三 | 上海 |
| 李四 | 上海 |
| 王五 | 北京 |
分组结果:
| city | count |
|---|---|
| 上海 | 2 |
| 北京 | 1 |
GROUP BY通常和聚合函数一起使用,例如:
count()、sum()、avg()、max()、min()
7. JOIN是什么?⭐⭐⭐⭐
用于多张表之间进行关联查询。常见JOIN类型有
inner join(内连接)
只返回两个表都有的数据
left join(左连接)
返回左表全部数据,以及右表匹配数据
Day 2:MySQL索引 ⭐
1. 什么是索引?(必背)
索引是一种帮助数据库快速查询数据的数据结构,主要用于提高数据库的查询效率,减少全表扫描
2. 为什么需要索引?
当数据量较大时,如果没有索引,数据库需要进行全表扫描,查询效率较低;
使用索引可以快速定位数据,提高查询效率。
3. 索引的底层结构是什么?⭐⭐⭐⭐
MySQL InnoDB存储引擎默认使用B+Tree作为索引结构。
🍉为什么使用B+Tree?
查询效率稳定、支持范围查询、树高度较低
4. 为什么不用二叉树?为什么不用Hash索引?⭐⭐⭐⭐
普通二叉树
如果使用普通二叉树、数据在有序的情况下、可能退化成链表。
时间复杂度变成O(n)、效率下降
Hash索引
优点:等值查询快。
缺点:
①不支持范围查询
②不支持排序
5. B+Tree是什么?⭐⭐⭐⭐⭐
B+Tree是一种多叉平衡搜索树,MySQL利用它来组织索引数据。
特点:
① 多叉:
一个节点可以存储多个关键字、因此树的高度比较低,可以减少磁盘I/O次数
② 所有数据存储在叶子节点
③ 叶子节点通过链表连接:方便范围查询
6. 索引的优缺点 ⭐⭐⭐⭐
优点:
① 提高查询效率,减少扫描数据。
② 提高排序效率
缺点:
① 占用额外空间,因为索引本身需要存储。
② 降低增删改效率,因为修改数据时,需要同时维护索引
7. 什么字段适合建立索引?⭐⭐⭐⭐
① 经常作为查询条件
② 经常排序
③ 经常用于JOIN查询
🍉什么字段不适合?
① 区分度比较低、重复值很多的字段
② 经常修改的字段
因为维护成本高。
8、为什么B+Tree特别适合范围查询?
做范围查询时,可以先通过B+Tree快速定位到范围起点,比如100,然后从这个叶子节点开始,沿着链表顺序向后扫描,直到200为止,所以范围查询效率比较高
9、那B+Tree和B树相比,有什么区别?为什么数据库更喜欢B+Tree?
B树的非叶子节点也可以存储数据;
而B+树的数据集中在叶子节点,非叶子节点主要用于索引。
这样B+树的非叶子节点可以容纳更多索引项,使树的高度更低;
同时B+树的叶子节点有序连接,因此更适合范围查询
Day 3:MySQL 索引进阶 🔥
1. 什么是聚簇索引?🔥🔥🔥
①聚簇索引是数据和索引存储在一起的索引。
②比如在InnoDB中,聚簇索引的叶子节点 存储完整的数据行
通常主键索引就是聚簇索引
2. 什么是二级索引?🔥🔥🔥
又叫:
非聚簇索引 / Secondary Index
二级索引的叶子节点一般不存完整数据行,而是存索引字段 + 主键值。
3. 什么是回表?什么是覆盖索引?🔥🔥🔥(高频)
回表是指通过二级索引查询时,其中没有查询所需要的全部字段,
就需要先通过二级索引找到主键值,再根据主键到聚簇索引中查询完整数据,
这个过程叫回表。
查询所需要的字段全部能够从索引中直接获得,
不需要再回表查询,这种情况叫覆盖索引
4. 什么是联合索引?什么是最左匹配原则?🔥🔥🔥🔥
联合索引:同时基于多个字段建立的索引
查询条件要尽量从联合索引最左边的字段开始匹配。
遇到范围查询后,范围字段可以使用索引,但其后的字段通常不能继续用于缩小索引扫描范围
5. 哪些情况可能导致索引失效?🔥🔥🔥🔥(高频)
① 违反联合索引最左匹配
② 对索引列进行函数操作
③ 对索引列进行计算
④ LIKE 以
%开头
6. 为什么不建议select *?🔥🔥
①可能增加不必要的数据读取
②并可能导致无法利用覆盖索引
③增加回表查询成本
7、为什么①通常可以正常利用索引,而②对索引列使用函数后可能无法正常利用这个索引?
① where name = 'Felix'; ② where lower(name) = 'felix';索引存的是原始值的有序结构,但查询条件用的是计算后的值,
因此数据库可能无法直接根据原索引定位数据
后
%:开头确定,知道从哪找。
前%:开头不确定,不知道从哪找。
where name = 'Felix' and age = 20 and city > '上海';最左匹配:
①中间缺字段会断;
②遇到范围查询,范围列能用,但后面的列不能继续用于缩小联合索引的扫描范围。
Day 4:MySQL 事务篇 🧩
1. 什么是事务?💎为什么需要事务?🔷
事务是一组数据库操作的集合,这些操作要么全部成功,要么全部失败,用来保证数据的一致性和可靠性
(防止执行过程中出现异常导致数据处于错误状态)
3. 事务MySQL中怎么使用?🔷
start transaction 开始事务 commit 提交事务 rollback 回滚事务4. 什么是 ACID?💎💎
事务有四大特性:
原子性:Atomicity
一个事务中的操作要么全部成功,要么全部失败。
一致性:Consistency
事务执行前后,数据都应该保持合法、一致的状态(总金额)
隔离性:Isolation
多个事务并发执行时,事务之间应该尽量互不干扰
持久性:Durability
事务一旦commit提交成功,修改的数据就应该被持久保存。
5. 并发事务会出现什么问题?💎💎
① 脏读 💎
一个事务读到了另一个事务还没有提交的数据。
②不可重复读 💎
同一个事务中,对同一条数据读取两次,结果不一样。
③幻读 💎
在同一个事务中,使用相同的查询条件进行多次查询,得到的记录集合不一致。
6. MySQL事务隔离级别 💎💎
隔离级别 | 中文 | 简单理解 |
|---|---|---|
Read Uncommitted | 读未提交 | 别人没提交我也能读 |
Read Committed | 读已提交 | 只能读别人已提交的数据 |
Repeatable Read | 可重复读 | 同一事务中重复读取保持一致 |
Serializable | 串行化 | 事务高度串行执行 |
7. MySQL InnoDB 默认隔离级别 💎💎
InnoDB 默认事务隔离级别是 Repeatable Read(RR,可重复读)
8. 四种隔离级别解决什么问题?💎
隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
Read Uncommitted | ❌可能 | ❌可能 | ❌可能 |
Read Committed | ✅解决 | ❌可能 | ❌可能 |
Repeatable Read | ✅解决 | ✅解决 | ⚠️标准定义下仍需关注幻读;InnoDB有额外机制处理许多幻读场景 |
Serializable | ✅ | ✅ | ✅ |
Day 5:MVCC + MySQL 锁 🛡️
1、什么是 MVCC?🔥🔥🔥
Multi-Version Concurrency Control,多版本并发控制。
MVCC是一种并发控制机制,
一条数据维护多个版本,让不同事务读取适合自己的版本,提高并发性能
2 、为什么需要 MVCC?🔥🔥🔥
你改你的新版本,我读我的旧版本,大家尽量别互相等。
3、undo log的两大作用:
undo log
①是回滚日志,主要用于事务回滚。
②帮助构建历史版本链。
MVCC 可以基于这些版本链,让不同事务读取自己想要的版本。
4、Read View
Read View 相当于一套可见性规则,用来判断版本链中的哪些数据版本能被当前事务读取
🍉为什么 InnoDB 的 Repeatable Read(可重复读)能够解决不可重复读问题?请从undo log、MVCC、版本链和 Read View 的角度解释。
undo log 记录数据修改前的相关信息,帮助构建版本链。Read View 是一套可见性规则,用于判断版本链中哪些数据能被当前事务读取。
RR 下同一个事务会保持一致的Read View,所以即使其他事务修改并提交了数据,我还是可以读取之前对我可见的版本,从而实现可重复读。
5、什么是快照读和当前读?🔥🔥🔥
快照读读取的是 MVCC 中对当前事务可见的数据版本;
当前读读取的是当前最新的数据,通常需要加锁。
6、什么是共享锁和排他锁?
共享锁(Shared Lock,S锁)
允许多个事务同时读取同一份数据,但会限制其他事务对该数据进行修改
排他锁(Exclusive Lock,X锁)
加了X锁后,其他事务不能再获取其它S锁或X锁,需要等待当前事务释放锁。
表锁 vs 行锁
表锁是锁住整张表,锁粒度比较大,并发性能相对低;
行锁是锁定具体的索引记录,锁粒度更小,并发性能更好。
(锁粒度 = 锁的范围大小)
记录锁(Record Lock)vs 间隙锁(Gap Lock)
Record Lock:锁住某一条具体的索引记录。
Gap Lock: 锁住两条索引记录之间的间隙
为啥(临键锁) Next-Key Lock 能帮助防止幻读?🔥🔥🔥🔥
Next-Key Lock 是 Record Lock 和 Gap Lock 的结合。
它既可以锁住已有的索引记录,又可以锁住记录之间的间隙,从而阻止其他事务在相应范围内插入新的记录,因此可以帮助防止幻读。
7、InnoDB 在 RR 隔离级别下,是怎么处理幻读问题的?
InnoDB 在 RR 隔离级别下主要通过MVCC和锁机制处理幻读场景。
①对于普通快照读,通过 MVCC、版本链和 Read View 保持 数据的一致
②对于当前读,则通过 Gap Lock、Next-Key Lock 等锁机制锁住相应的索引范围和间隙,防止其他事务插入新的记录,从而处理幻读问题。
8、为什么说 InnoDB 的查询条件如果没有合适的索引,可能导致“锁范围扩大”,甚至表现得像锁表?
如果查询条件没有合适的索引,可能需要进行全表扫描,并锁住大量扫描到的索引记录,导致锁范围扩大,影响并发性能。
🍉什么情况下行锁可能退化成类似“锁表”的效果?
查询/更新条件中的字段没有合适的索引。
🍉快照读 && 当前读
普通 SELECT 一般属于快照读,通过 MVCC 和 Read View 读取当前事务可见的数据版本;
SELECT ... FOR UPDATE 属于当前读,会读取最新的数据版本,并对相关记录加锁。
9、为什么SELECT ... FOR UPDATE不能像普通 SELECT 一样只读取历史快照,而要读取当前最新的数据并加锁?
因为
SELECT ... FOR UPDATE通常是为了后续修改数据,所以需要读取当前最新的数据,并对相关记录加锁,防止其他事务同时进行冲突修改。
🍉事务 ACOMMIT之后,事务 B 会发生什么?
COMMIT 不仅提交事务的数据修改,还会释放该事务持有的锁。
🍉如果事务 A 还是持有X Lock,但事务 B 执行select
事务 B 会不会被阻塞?为什么?
事务 B 通常不会被阻塞,因为普通
SELECT属于快照读,它通过 MVCC,根据 Read View 的可见性规则,从版本链中读取当前事务可见的数据版本。
Day6:SQL 优化与 EXPLAIN 🔥🔥🔥🔥
第一题 🔥🔥🔥:什么是慢 SQL?
慢 SQL(执行时间较长、执行效率较低的 SQL) → 慢查询日志定位具体SQL → EXPLAIN 分析执行计划 → 重点看四个字段 → 针对性优化
(比如建立或调整合适的索引、优化联合索引、避免索引失效、减少
SELECT *、优化深分页等。优化之后再重新通过 EXPLAIN 和实际执行情况验证优化效果。)
第二题 🔥🔥🔥🔥:EXPLAIN 是干什么的?
MySQL 打算怎么执行这条 SQL?
type → 怎么找数据的?
key → 本次执行实际使用的索引
rows →预计扫描的行数
Extra → 还有什么额外执行信息?
第三题 🔥🔥🔥🔥:
type = ALL:扫描整张表
type = index:MySQL 需要扫描整棵索引
type = range:只扫描符合条件的一段索引范围,而不是扫描整棵索引
type = ref:通过普通索引进行等值匹配,可能匹配到多条记录
type = const:通过主键索引或唯一索引进行等值查询,并且最多只匹配一条记录
🔥一般至少希望查询达到 range 级别,最好能达到 ref;
出现 index、ALL 时需要重点关注,但不是看到 ALL 就一定有问题。
为什么不能看到key != NULL、SQL 使用了索引,就直接判断“这条 SQL 性能很好”?
结合rows
为什么Extra = Using index通常是一个比较好的信号?
Using index → 使用了覆盖索引 ⭐
Using where → 还需要根据 WHERE 条件进行过滤
Using filesort→ 需要额外进行排序 🚨
Using temporary→ 使用了临时表 🚨
第四题:SQL优化---深分页
SELECT * FROM orders ORDER BY id LIMIT 1000000, 10;
LIMIT offset, size在 offset 很大时会产生深分页问题,因为数据库需要扫描并丢弃前面大量数据,最终只返回少量记录,造成不必要的扫描开销。
优化后:
SELECT * FROM orders WHERE id > 1000000 !!! ORDER BY id LIMIT 10;Day7:InnoDB 底层 + MySQL 日志体系
1、什么是 Buffer Pool?InnoDB 为什么需要 Buffer Pool?
Buffer Pool 是 InnoDB 在内存中的缓冲区域,
用于缓存数据页等内容,减少磁盘 I/O,提高数据库性能。
2、是不是每执行一次UPDATE,MySQL 都要立刻把修改后的数据写回磁盘?
InnoDB 更新数据时,通常先修改 Buffer Pool,并记录 redo log,之后再把脏页刷回磁盘,而不是每次 UPDATE 都立即写磁盘。
① 脏页
这种已经被修改、但还没有刷回磁盘的数据页,叫脏页。
② redo log
记录“这次修改做了什么”,用于在数据库异常恢复时重新执行这些修改。
3、既然有了 redo log,为什么还需要 binlog?redo log 和 binlog 有什么区别?
redo log 主要用于InnoDB 的崩溃恢复;
binlog 主要用于主从复制和数据恢复
redo log 是 InnoDB 的日志,而 binlog 是 MySQL Server 层面的日志,
因此 MySQL 需要同时维护这两套日志。
4、为什么 MySQL 需要两阶段提交?
MySQL 使用两阶段提交,是为了保证 redo log 和 binlog 的一致性,避免出现一个日志已经记录事务提交、另一个日志却没有记录的情况。
5、redo log 为什么叫“循环写”? binlog叫“追加写”?
redo log 空间有限,通过循环写实现空间复用。
而 binlog 需要记录数据库的历史变更,用于主从复制和数据恢复,因此通常采用追加写的方式保存日志。
6、一个update的背后流程图
UPDATE ↓ ┌──────────────┐ │ Buffer Pool │ │ 修改数据页 │ └──────┬───────┘ ↓ 脏页 │ ┌──────┴──────┐ ↓ ↓ redo log binlog 崩溃恢复 复制/恢复 ↘ ↙ 两阶段提交 保证日志一致 ↓ 后续脏页刷盘