Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL面试核心知识点

MySQL面试核心知识点总结与原理详细解析

作者:路小雨~

这篇文章主要介绍了MySQL面试核心知识点总结与原理详细解析的相关资料,文中通过示例代码详细介绍了MySQL架构、索引、事务与MVCC、锁机制及三大日志,手把手带你掌握SQL优化与EXPLAIN分析,需要的朋友可以参考下

一、 MySQL 架构与基础

1. 核心架构层级

2. InnoDB vs MyISAM

维度InnoDB (默认)MyISAM原理解释 (面试官追问:为什么这样设计?)
事务✅ 支持❌ 不支持InnoDB 内部实现了 undo log 和 redo log 来保障 ACID 特性;MyISAM 设计之初只为了查询快,做成了轻量级。
锁粒度行级锁表级锁InnoDB 在索引加锁(Record Lock等),并发更新互不影响;MyISAM 直接锁整张表,并发写性能极差。
外键✅ 支持❌ 不支持维护数据完整性,但现代互联网高并发架构一般不用外键(由业务代码保证),避免数据库层面的级联更新和锁死。
恢复✅ 支持❌ 差InnoDB 靠 redo log 实现 Crash-safe(宕机恢复);MyISAM 宕机后极易损坏数据文件。
结构聚簇索引非聚簇索引InnoDB 的主键 B+ 树叶子节点存放真实数据行;MyISAM 的 B+ 树叶子节点存放数据文件的指针(内存地址)。

💻 演示:指定存储引擎

-- 创建一张使用 InnoDB 的表(MySQL 5.5 后默认)
CREATE TABLE user_innodb (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 创建一张使用 MyISAM 的表
CREATE TABLE user_myisam (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;

二、 索引 (Index)

1. 为什么使用 B+ 树?(底层原理解释)

2. 聚簇索引 vs 非聚簇索引(二级索引)

3. 回表与覆盖索引

💻 演示:回表与覆盖索引(核心必考)

-- 假设我们有表 user,主键是 id。我们给 name 字段加一个二级索引
CREATE INDEX idx_name ON user(name);

-- ❌ 发生回表:
-- 引擎先在 idx_name 树上找到 '张三' 对应的主键 id=1。
-- 但是你要查 age,idx_name 树上没有 age,只好拿 id=1 回到主键树(聚簇索引)再查一次。
SELECT id, name, age FROM user WHERE name = '张三';

-- ✅ 覆盖索引 (Extra: Using index):
-- 你要查的 id 和 name,在 idx_name 这棵树的叶子节点上都已经有了!
-- 直接返回数据,不需要再去主键树查,性能极高。
SELECT id, name FROM user WHERE name = '张三';

-- 💡 进阶:如何让第一条 SQL 也变成覆盖索引?建立联合索引!
CREATE INDEX idx_name_age ON user(name, age);
-- 此时再去查 name 和 age,就全是覆盖索引了。

4. 最左前缀原则

💻 演示:最左前缀原则的生效与失效

-- 创建联合索引 (a, b, c)
CREATE INDEX idx_a_b_c ON test_table(a, b, c);

-- ✅ 完美走索引:从左到右连续匹配
SELECT * FROM test_table WHERE a = 1 AND b = 2 AND c = 3;
SELECT * FROM test_table WHERE a = 1 AND b = 2;
SELECT * FROM test_table WHERE a = 1;

-- ❌ 完全不走索引:跳过了最左边的 a
SELECT * FROM test_table WHERE b = 2 AND c = 3;

-- ⚠️ 部分走索引:中间断开或者遇到范围查询
SELECT * FROM test_table WHERE a = 1 AND c = 3;       -- a 走索引,c 断层不走索引
SELECT * FROM test_table WHERE a = 1 AND b > 10 AND c = 3; -- a 走索引,b 走索引(找范围),c 不走索引(范围之后失效)

三、 事务与 MVCC

1. 事务 ACID 特性及实现原理

💻 演示:脏读、不可重复读、幻读究竟长啥样?

-- 查看当前隔离级别
SELECT @@transaction_isolation;
-- 设置隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 👻 场景:脏读 (发生在 读未提交 RU 级别)
-- 事务 A:
BEGIN;
UPDATE account SET balance = balance - 100 WHERE id = 1; -- 扣钱,但还没提交!
-- 事务 B:
SELECT balance FROM account WHERE id = 1; -- 查到了扣完的钱。如果A马上回滚,B查到的就是脏数据!

-- 👻 场景:不可重复读 (发生在 读已提交 RC 级别)
-- 事务 A: 
BEGIN;
SELECT balance FROM account WHERE id = 1; -- 第一次读:1000
-- 事务 B:
BEGIN; UPDATE account SET balance = 500 WHERE id = 1; COMMIT; -- 别人改了并提交
-- 事务 A:
SELECT balance FROM account WHERE id = 1; -- 第二次读:500!(同一个事务内,越读越少,见鬼了)

-- 👻 场景:幻读 (发生在 可重复读 RR 级别)
-- 事务 A:
BEGIN;
SELECT COUNT(*) FROM user WHERE age > 20; -- 查出 5 个人
-- 事务 B:
BEGIN; INSERT INTO user(age) VALUES (25); COMMIT; -- 别人悄悄塞了一个人进去
-- 事务 A:
UPDATE user SET status = 1 WHERE age > 20; -- !!发现竟然更新了 6 条数据 (见鬼了,多出来个幻象)

2. MVCC (多版本并发控制) 底层原理

[!IMPORTANT]
原理解释:如果单纯用锁来保证隔离性(读也加锁,写也加锁),并发效率就太低了。MVCC 的核心目的就是**“读写不冲突”。当别人在写数据时,我不去阻塞他,而是去读这条数据的历史版本快照**。

四、 锁机制 (Lock)

1. InnoDB 的行锁原理解析

💻 演示:如何手动加锁?

BEGIN;
-- 加共享锁 (S锁,读锁):我读的时候,别人也能读(加S锁),但别人不能改(加X锁)
SELECT * FROM user WHERE id = 1 LOCK IN SHARE MODE;

-- 加排他锁 (X锁,写锁):我在看/改的时候,别人连加S锁都不行,属于唯我独尊
SELECT * FROM user WHERE id = 1 FOR UPDATE;

UPDATE user SET age = 20 WHERE id = 1; -- UPDATE 语句隐式自动加排他锁(X锁)
COMMIT;

2. 表锁降级陷阱及其原理

3. 间隙锁防幻读 与 表锁降级大坑

💻 演示:Next-Key Lock 锁间隙(防幻读)

-- 表里只有 id = 1, 5, 10
-- 事务 A 在 RR 隔离级别下:
BEGIN;
SELECT * FROM user WHERE id > 1 AND id < 10 FOR UPDATE;
-- 此时不仅仅 id=5 这行被锁住了。
-- (1, 5) 和 (5, 10) 这两个间隙也被锁死了!

-- 事务 B:
INSERT INTO user (id) VALUES (3); -- ⛔ 被阻塞!插入不进去,从而防止了事务 A 发生幻读!

💻 演示:灾难级的面试真题 —— 行锁变表锁!

-- ⚠️ 假设 name 字段没有建索引!
BEGIN;
UPDATE user SET age = 30 WHERE name = '张三'; 
-- 灾难发生:因为 name 没索引,MySQL 无法定位具体哪行,只能在主键树上全表扫描。
-- 扫描的过程中,会把所有途径的记录和间隙全锁上!
-- 导致其他任何事务连 UPDATE 李四、甚至 INSERT 王五 都会被阻塞挂起!等同于表锁!

五、 MySQL 三大日志系统深度融合

日志谁写的记录内容 (原理解释)核心作用特性
redo logInnoDB物理日志:在第 xx 个数据页,偏移量 yy 的位置,把值改成了张三。
它记录的是底层的“手术动作”。
崩溃恢复 (Crash-safe)。
有了它,修改内存就算没刷盘宕机了,重启照样能靠重做恢复。
空间固定,循环写 (旧日志刷盘后会被覆盖)。采用 WAL 先写日志后写磁盘技术提升IO。
undo logInnoDB逻辑日志:你执行 INSERT,它记 DELETE;你执行 UPDATE a=2,它记 UPDATE a=1。1. 事务回滚 (保证原子性)
2. 形成 MVCC 的历史版本链。
事务产生修改时写入,随版本链回收。
binlogServer层逻辑日志:执行了 UPDATE ... WHERE id = 1 这样的SQL。1. 主从同步 (从库解析SQL照做)
2. 数据恢复 (重放整个建库历史)
不限空间,追加写 (不覆盖旧日志)。

核心面试大题:为什么需要两阶段提交 (2PC)?

六、 SQL 优化与 EXPLAIN 分析

1. EXPLAIN 深层理解

💻 演示:查看执行计划

EXPLAIN SELECT u.name, o.order_no 
FROM user u 
JOIN orders o ON u.id = o.user_id 
WHERE u.age = 20;

重点盯防:

2. 索引失效背后的原理解析

💻 演示:明明建了索引,为什么不用?

-- 假设我们在 create_time, phone, name 上都建了单列索引

-- ❌ 对列用函数:B+ 树原本按日期字符串排的,被 YEAR 一搞全乱了
SELECT * FROM table WHERE YEAR(create_time) = 2024; 
-- ✅ 正确写法:
SELECT * FROM table WHERE create_time >= '2024-01-01' AND create_time < '2025-01-01';

-- ❌ 隐式类型转换:phone 是 VARCHAR 字符串类型,你传了数字!MySQL 底层偷偷给你套了个 CAST 函数,索引直接失效
SELECT * FROM table WHERE phone = 13800138000;
-- ✅ 正确写法:加上单引号
SELECT * FROM table WHERE phone = '13800138000';

-- ❌ LIKE 左模糊:第一字符都不确定,字典没法查
SELECT * FROM table WHERE name LIKE '%三';
-- ✅ 右模糊可以走索引:先锁定一部分开头的人再去慢慢查
SELECT * FROM table WHERE name LIKE '张%';

3. 高级 SQL 优化原理解析

总结 

到此这篇关于MySQL面试核心知识点总结与原理详细解析的文章就介绍到这了,更多相关MySQL面试核心知识点内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文