MySQL 高频面试题 30 问:索引、事务、锁、日志、主从与分库分表(MySQL 8.0 版)

个人主页: > for_ever_love__ <(欢迎各位大佬莅临😊)
其他栏目: > 大模型开发从0到1 <
其他栏目: > iOS项目总结大全 <
其他栏目: > 我想学python了 <
其他栏目: > iOS UI <

文章目录

  • [MySQL 高频面试题 30 问:索引、事务、锁、日志、主从与分库分表(MySQL 8.0 版)](#MySQL 高频面试题 30 问:索引、事务、锁、日志、主从与分库分表(MySQL 8.0 版))
    • [一、索引篇(Q1 - Q8)](#一、索引篇(Q1 - Q8))
    • [二、事务与锁篇(Q9 - Q14)](#二、事务与锁篇(Q9 - Q14))
      • [Q9:ACID 分别靠什么实现?](#Q9:ACID 分别靠什么实现?)
      • [Q10:四种隔离级别,MySQL 默认哪个?](#Q10:四种隔离级别,MySQL 默认哪个?)
      • [Q11:MVCC 是怎么实现的?RC 和 RR 的差别在哪?](#Q11:MVCC 是怎么实现的?RC 和 RR 的差别在哪?)
      • Q12:快照读和当前读有什么区别?
      • [Q13:InnoDB 有哪几种锁?什么是 Next-Key Lock?](#Q13:InnoDB 有哪几种锁?什么是 Next-Key Lock?)
      • Q14:死锁怎么排查和避免?
    • [三、日志与存储篇(Q15 - Q19)](#三、日志与存储篇(Q15 - Q19))
      • [Q15:redo log、undo log、binlog 有什么区别?](#Q15:redo log、undo log、binlog 有什么区别?)
      • Q16:为什么要有"两阶段提交"?
      • [Q17:一条 UPDATE 语句在 MySQL 里经历了什么?](#Q17:一条 UPDATE 语句在 MySQL 里经历了什么?)
      • [Q18:InnoDB 和 MyISAM 的区别?](#Q18:InnoDB 和 MyISAM 的区别?)
      • [Q19:为什么 8.0 移除了查询缓存(Query Cache)?](#Q19:为什么 8.0 移除了查询缓存(Query Cache)?)
    • [四、SQL 优化篇(Q20 - Q24)](#四、SQL 优化篇(Q20 - Q24))
      • [Q20:深分页 `LIMIT 1000000, 20` 为什么慢?怎么优化?](#Q20:深分页 LIMIT 1000000, 20 为什么慢?怎么优化?)
      • [Q21:JOIN 有哪些算法?](#Q21:JOIN 有哪些算法?)
      • [Q22:GROUP BY 和 ORDER BY 什么时候会用到临时表 / filesort?](#Q22:GROUP BY 和 ORDER BY 什么时候会用到临时表 / filesort?)
      • Q23:慢查询的排查流程是什么?
      • [Q24:CHAR 和 VARCHAR 怎么选?`VARCHAR(10)` 能存 10 个汉字吗?](#Q24:CHAR 和 VARCHAR 怎么选?VARCHAR(10) 能存 10 个汉字吗?)
    • [五、架构与运维篇(Q25 - Q28)](#五、架构与运维篇(Q25 - Q28))
    • [六、场景题(Q29 - Q30)](#六、场景题(Q29 - Q30))
      • [Q29:一个表有 `(a, b, c)` 联合索引,下面几条 SQL 谁走索引?](#Q29:一个表有 (a, b, c) 联合索引,下面几条 SQL 谁走索引?)
      • [Q30:线上发现 CPU 100%,怎么定位?](#Q30:线上发现 CPU 100%,怎么定位?)
    • 小结:面试回答的三个层次

MySQL 高频面试题 30 问:索引、事务、锁、日志、主从与分库分表(MySQL 8.0 版)

面试 MySQL 有个特点:题目就那些,但每一问都能往下追三层。

只会背"ACID 是原子性一致性隔离性持久性"的人,第一层就结束了。

这篇按模块整理 30 个高频问题,每题给出能答到第二层的答案 和常见的追问点 。

默认语境是 MySQL 8.0 + InnoDB,遇版本差异会单独标注。

一、索引篇(Q1 - Q8)

Q1:为什么索引用 B+ 树,而不是二叉查找树或 B 树?

结构 问题
二叉查找树 可能退化成链表,树高 = n
平衡二叉树(AVL/红黑树) 每个节点只存一个 key,树高太高。100 万行数据树高约 20,就要 20 次磁盘 IO
B 树 多叉,树高降低;但每个节点都存数据,一个页能放的 key 变少,树高反而更高
B+ 树 ✅ 非叶子节点只存 key 不存数据 ,一个 16KB 的页能塞上千个 key → 树高只有 3~4 层;且叶子节点用链表串起来,范围查询不用回溯到根

一句话总结 :B+ 树把"树高"压到 3~4 层,意味着亿级数据点查只需 3~4 次磁盘 IO ;

叶子链表让它天然擅长范围查询。

追问:为什么不用 Hash 索引?------ Hash 只支持等值查询,不支持范围和排序 ,

且有哈希冲突。InnoDB 的自适应哈希索引(AHI)是内部优化,用户不能显式创建(MEMORY 引擎除外)。

Q2:聚簇索引和二级索引有什么区别?什么是回表?

  • 聚簇索引 :叶子节点存整行数据。InnoDB 每张表有且仅有一个,通常是主键
  • 二级索引 :叶子节点存索引列 + 主键值

通过二级索引找到主键值后,再去聚簇索引查整行,这个过程叫回表。

sql 复制代码
-- 假设 idx_name 建在 name 上
SELECT * FROM user WHERE name = '张三';
-- ① 走 idx_name 找到主键 id=100
-- ② 用 id=100 回聚簇索引取整行      ← 回表

减少回表的办法就是覆盖索引:

sql 复制代码
-- 建联合索引,让查询需要的列都在索引里
CREATE INDEX idx_name_age ON user(name, age);
SELECT id, name, age FROM user WHERE name = '张三';   -- Extra: Using index,不用回表

Q3:联合索引的最左前缀原则是怎么回事?

索引 (a, b, c) 在 B+ 树里是按 a → b → c 的顺序排序的,

所以只能从最左边开始"连续"匹配:

条件 能否用上索引 用到哪些列
a = 1 ✅ a
a = 1 AND b = 2 ✅ a, b
a = 1 AND b = 2 AND c = 3 ✅ a, b, c
b = 2 ❌ 无(没有 a,无法定位)
a = 1 AND c = 3 部分 只有 a(b 断掉了)
a > 1 AND b = 2 部分 只有 a(范围条件之后的列用不上)

⚠️ 8.0 的索引跳跃扫描(Index Skip Scan) 可以在没有最左列时"跳着"用索引,

但只在该列基数很低(比如性别只有 2 个值)时才划算,不能依赖它。

Q4:哪些情况会导致索引失效?

场景 例子 说明
索引列上用函数 WHERE YEAR(create_time) = 2024 改成范围条件
隐式类型转换 WHERE phone = 13800138000(phone 是 varchar) 字符串列传了数字,全表扫
隐式字符集转换 两表 JOIN 字段字符集不同 utf8mb4 JOIN utf8 会失效
LIKE '%xxx' WHERE name LIKE '%三' 前缀通配符无法定位;'三%' 可以
OR 连接非索引列 WHERE a=1 OR b=2(b 无索引) 改成 UNION 或给 b 加索引
违反最左前缀 见 Q3 ---
优化器判断不划算 结果集占比太高 回表代价大于全表扫描,优化器会选全表
sql 复制代码
-- ❌ 失效
SELECT * FROM orders WHERE DATE(create_time) = '2024-06-01';
-- ✅ 改写
SELECT * FROM orders WHERE create_time >= '2024-06-01' AND create_time < '2024-06-02';

Q5:什么是索引下推(ICP)?

MySQL 5.6 引入。联合索引 (name, age),查询 WHERE name LIKE '张%' AND age = 20:

  • 没有 ICP :存储引擎只按 name LIKE '张%' 返回所有匹配行,Server 层再过滤 age
  • 有 ICP :存储引擎在索引内部就顺手判断 age=20,不符合的直接跳过,减少回表次数

执行计划里表现为 Extra: Using index condition。

8.0 默认开启,可用 optimizer_switch='index_condition_pushdown=off' 关闭验证。

Q6:EXPLAIN 里你主要看哪几列?

列 关注点
type 从优到劣:system > const > eq_ref > ref > range > index > ALL。见到 ALL 和 index 就要警惕
key 实际用到的索引;possible_keys 有但 key 为 NULL 说明索引没被选中
rows 预估扫描行数,与实际返回行数差太多说明统计信息不准
Extra Using index(覆盖索引,好)、Using filesort(排序没走索引)、Using temporary(用了临时表,通常要优化)
filtered 8.0 有,表示经过条件过滤后剩余的比例
sql 复制代码
EXPLAIN FORMAT=JSON SELECT ...;   -- 更详细,含 cost 估算
EXPLAIN ANALYZE SELECT ...;       -- 8.0.18+,给出真实执行耗时和行数

Q7:COUNT(*)、COUNT(1)、COUNT(列) 有什么区别?

写法 行为 性能
COUNT(*) 统计所有行数 8.0 对 COUNT(*) 有特殊优化,通常最快
COUNT(1) 与 COUNT(*) 几乎等价 基本一样
COUNT(列) 统计该列非 NULL 的行数 可能慢,且语义不同
COUNT(主键) 统计主键非 NULL 行数 主键非空,等于总行数

结论 :直接用 COUNT(*),别再纠结 COUNT(1) 的都市传说了。

追问:InnoDB 为什么不把总行数存起来?------ 因为 MVCC,不同事务看到的行数不一样,没法存一个全局值。

Q8:为什么推荐用自增 ID 做主键,UUID 有什么问题?

维度 自增 ID UUID
插入性能 顺序写,页分裂少 随机写,频繁页分裂,产生碎片
索引体积 8 字节(BIGINT) 36 字节(字符串)或 16 字节(BINARY(16))
聚簇索引 紧凑 二级索引都要存主键,主键大则所有索引都变大
分布式 需要额外方案(雪花、号段) 天然全局唯一
安全性 可推测,有信息泄露风险 安全

关键原因是"页分裂" :InnoDB 数据按主键顺序存,随机主键会让新行插到已有页中间,

页满了就分裂、移动数据,产生碎片并降低页填充率。

追问:8.0 能用 UUID_TO_BIN(uuid(), 1) 存成 BINARY(16) 并且把时间部分提前 ,

从而让 UUID 变得相对有序,缓解这个问题。

二、事务与锁篇(Q9 - Q14)

Q9:ACID 分别靠什么实现?

特性 实现机制
原子性 Atomicity undo log(回滚日志)
一致性 Consistency 前三者共同保证 + 应用逻辑
隔离性 Isolation MVCC + 锁
持久性 Durability redo log

Q10:四种隔离级别,MySQL 默认哪个?

级别 脏读 不可重复读 幻读
READ UNCOMMITTED ❌可能 ❌可能 ❌可能
READ COMMITTED ✅ ❌可能 ❌可能
REPEATABLE READ(MySQL 默认) ✅ ✅ ✅ InnoDB 下靠间隙锁解决
SERIALIZABLE ✅ ✅ ✅

MySQL 默认 RR,Oracle / PostgreSQL 默认 RC,这是常被对比的点。

Q11:MVCC 是怎么实现的?RC 和 RR 的差别在哪?

MVCC = undo log 版本链 + ReadView。

每行有三个隐藏字段:DB_TRX_ID(最后修改的事务 ID)、DB_ROLL_PTR(回滚指针)、DB_ROW_ID。

通过 DB_ROLL_PTR 把历史版本串成一条链,读的时候按 ReadView 规则挑一个可见版本。

RC 和 RR 唯一的实现差异是 ReadView 生成时机:

级别 ReadView 生成时机 效果
RC 每条 SELECT 都重新生成 每次看到最新已提交数据 → 不可重复读
RR 事务内第一次 SELECT 时生成,之后复用 整个事务看同一个快照 → 可重复读

Q12:快照读和当前读有什么区别?

sql 复制代码
SELECT * FROM t WHERE id = 1;              -- 快照读,走 MVCC,不加锁
SELECT * FROM t WHERE id = 1 FOR UPDATE;   -- 当前读,加排他锁,读最新版本
UPDATE t SET a = 1 WHERE id = 1;           -- UPDATE 本质是当前读

⚠️ 经典坑 :在 RR 下 SELECT 看到 1000,别的事务改成 900 并提交,

你再 UPDATE ... SET balance = balance - 100,UPDATE 是当前读,会基于 900 算 。

所以"先读后写"必须用 FOR UPDATE 加锁,否则丢失更新。

Q13:InnoDB 有哪几种锁?什么是 Next-Key Lock?

锁类型 说明
行锁 Record Lock 锁单条索引记录
间隙锁 Gap Lock 锁两条记录之间的间隙,防止插入
Next-Key Lock 行锁 + 间隙锁,左开右闭区间,RR 下的默认加锁单位
意向锁 IS / IX 表级锁,用于快速判断表里有没有行锁
自增锁 AUTO-INC 插入自增列时的特殊表级锁

间隙锁是 RR 下解决幻读的关键 。RR 下 SELECT ... FOR UPDATE 会加 Next-Key Lock,

阻止别的事务在区间内插入,所以"当前读"也不会出现幻读。

⚠️ RC 下基本没有间隙锁 (只剩外键和唯一性检查场景),

这是很多团队把 MySQL 改成 RC 的原因:锁范围小、死锁少、并发高。

Q14:死锁怎么排查和避免?

sql 复制代码
-- 查看最近一次死锁(只保留最后一条)
SHOW ENGINE INNODB STATUS\G
-- 建议打开配置,把所有死锁写进 error log
SET GLOBAL innodb_print_all_deadlocks = ON;

死锁产生的四个必要条件 :互斥、占有且等待、不可抢占、循环等待。

破坏任意一个即可,工程上最有效的是破坏循环等待:

  • 所有业务按固定顺序访问资源(比如先扣 A 账户再扣 B 账户,永远按 id 排序)
  • 缩小事务范围,把查询逻辑移到事务外
  • 避免长事务,避免事务里有 RPC / 慢查询
  • 合理设置 innodb_lock_wait_timeout(默认 50s,可降到 10~30s 快速失败)

三、日志与存储篇(Q15 - Q19)

Q15:redo log、undo log、binlog 有什么区别?

redo log undo log binlog
层级 InnoDB 引擎层 InnoDB 引擎层 MySQL Server 层
作用 崩溃恢复,保证持久性 回滚 + MVCC 版本链 主从复制、数据恢复
内容 物理日志(页的修改) 逻辑日志(反向操作) 逻辑日志(SQL 或行变更)
写入方式 循环写,固定大小 随事务生成 追加写,可归档
所有引擎都有 ❌ ❌ ✅

Q16:为什么要有"两阶段提交"?

redo log 和 binlog 是两套独立的日志,必须保证它们状态一致,否则主从会不一致。

复制代码
1. prepare 阶段:redo log 写入并标记 prepare
2. 写 binlog
3. commit 阶段:redo log 标记 commit

崩溃恢复时的判断逻辑:

  • redo 里有 commit 标记 → 提交
  • redo 里只有 prepare,但能找到对应 binlog → 提交
  • redo 里只有 prepare,找不到 binlog → 回滚

Q17:一条 UPDATE 语句在 MySQL 里经历了什么?

复制代码
1. 连接器:权限校验
2. 分析器:词法、语法分析
3. 优化器:选索引、定执行计划(基于 cost)
4. 执行器:调用 InnoDB 接口
   ├─ 数据页在 Buffer Pool?不在就从磁盘加载
   ├─ 写 undo log
   ├─ 更新 Buffer Pool 中的数据页(变脏页)
   ├─ 写 redo log(prepare)
   ├─ 写 binlog
   └─ redo log 标记 commit
5. 后台线程异步刷脏页

⚠️ 注意顺序:先改内存,再写日志,这就是 WAL(Write-Ahead Logging)。

Q18:InnoDB 和 MyISAM 的区别?

维度 InnoDB MyISAM
事务 ✅ ❌
锁粒度 行锁 表锁
外键 ✅ ❌
崩溃恢复 ✅(redo log) ❌
MVCC ✅ ❌
索引结构 聚簇索引,数据即索引 非聚簇,索引存物理地址
行数统计 不保存,COUNT(*) 要扫 保存,COUNT(*) 极快
全文索引 5.6+ 支持 支持
8.0 分区 ✅ 唯一支持分区的主流引擎 ❌ 8.0 已移除分区支持

结论:除非只读且不需要事务(极少见),一律用 InnoDB。 5.5 之后它就是默认引擎。

Q19:为什么 8.0 移除了查询缓存(Query Cache)?

查询缓存在 5.7 默认关闭,8.0 直接移除。原因:

  • 缓存失效太激进:表里任何一行改动,该表所有缓存全部失效
  • 写多读少的场景下,维护缓存的开销大于收益
  • 有全局锁竞争,是并发瓶颈

现在这个活儿交给应用层(Redis)或者用 Buffer Pool 缓存数据页(粒度更细、更有效)。

四、SQL 优化篇(Q20 - Q24)

Q20:深分页 LIMIT 1000000, 20 为什么慢?怎么优化?

MySQL 必须先扫描并丢弃前 1000000 行,只返回后 20 行。

sql 复制代码
-- ❌ 慢
SELECT * FROM orders ORDER BY id LIMIT 1000000, 20;

-- ✅ 方案一:延迟关联(用覆盖索引先拿到 id)
SELECT o.* FROM orders o
JOIN (SELECT id FROM orders ORDER BY id LIMIT 1000000, 20) t ON o.id = t.id;

-- ✅ 方案二:游标分页(推荐,尤其无限下拉场景)
SELECT * FROM orders WHERE id > 1000000 ORDER BY id LIMIT 20;

方案二最优,但要求排序键唯一且连续,且不支持"直接跳到第 N 页"。

Q21:JOIN 有哪些算法?

算法 版本 说明
Simple Nested Loop Join 老版本 双层循环,最差
Index Nested Loop Join 一直有 被驱动表走索引,最常见的最优路径
Block Nested Loop Join 5.x 被驱动表无索引时,用 join buffer 批量比对
Hash Join 8.0.18+ 无索引的等值 JOIN 场景下取代 BNL,性能大幅提升

优化要点:小表驱动大表 、被驱动表的 JOIN 字段必须有索引。

Q22:GROUP BY 和 ORDER BY 什么时候会用到临时表 / filesort?

  • ORDER BY 的字段顺序、升降序与索引不一致 → Using filesort
  • GROUP BY 的字段没有合适索引 → Using temporary + Using filesort
  • 8.0 之前 GROUP BY 会隐式排序,8.0 起不再默认排序(除非显式写 ORDER BY)
sql 复制代码
-- 建 (status, create_time) 联合索引,下面这条就能直接走索引有序性
SELECT status, COUNT(*) FROM orders GROUP BY status;

Q23:慢查询的排查流程是什么?

sql 复制代码
-- 1. 开启慢日志
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;

-- 2. 找出最慢的 SQL
SELECT DIGEST_TEXT, COUNT_STAR, AVG_TIMER_WAIT/1e12 AS avg_sec
FROM performance_schema.events_statements_summary_by_digest
ORDER BY AVG_TIMER_WAIT DESC LIMIT 10;

-- 3. EXPLAIN 分析
EXPLAIN SELECT ...;

-- 4. 看优化器到底怎么选的
SET optimizer_trace = 'enabled=on';
SELECT ...;
SELECT * FROM information_schema.OPTIMIZER_TRACE\G

排查顺序一般是:有没有走索引 → 扫描行数是否过大 → 有没有 filesort/临时表 → 能不能改写 SQL。

Q24:CHAR 和 VARCHAR 怎么选?VARCHAR(10) 能存 10 个汉字吗?

CHAR(n) VARCHAR(n)
长度 固定,右边补空格 可变
检索 尾部空格被去掉 保留
额外开销 无 1~2 字节长度前缀
适用 长度几乎固定的短串(如状态码、MD5、手机号) 长度变化大的字符串

VARCHAR(10) 能存 10 个"字符" ,utf8mb4 下一个汉字 4 字节,所以实际占 40 字节 + 前缀。

括号里的数字是字符数不是字节数,这是 MySQL 5.0 之后的约定。

追问:INT(11) 的 11 是什么?------显示宽度 ,只影响 ZEROFILL 时的补零,

不改变存储范围(INT 永远是 4 字节)。8.0.17 起该显示宽度属性已废弃。

五、架构与运维篇(Q25 - Q28)

Q25:主从复制的原理是什么?延迟怎么解决?

复制代码
主库:事务提交时写 binlog(binlog dump 线程负责推送)
从库:IO 线程拉取 binlog 写入 relay log
从库:SQL 线程回放 relay log

延迟的常见原因:

原因 解法
从库单线程回放跟不上 开并行复制:replica_parallel_workers=8 + LOGICAL_CLOCK
主库有大事务 拆分大事务,一次删 100 万行改成每次 1 万行
从库硬件比主库差 从库配置不低于主库
从库承担大量读查询 分流,降低从库负载
无主键表,ROW 模式下回放慢 所有表必须有主键

Q26:读写分离会遇到什么问题?

最典型的是主从延迟导致"刚写完读不到":

方案 说明
写后读主库 关键业务(下单后查订单)强制走主库
二次读取 从库读不到再读一次主库
缓存标记 写操作后打标记,短时间内读主库
等 GTID 8.0 可用 WAIT_FOR_EXECUTED_GTID_SET() 等从库追上(牺牲延迟换一致性)

Q27:大表加一个字段,怎么做到不影响业务?

优先级从高到低:

  1. 8.0.12+ 的 INSTANT ADD COLUMN:只改数据字典,秒级完成,首选
  2. gh-ost / pt-osc:5.7 或需要改类型时的标准方案
  3. 原生 Online DDL(INPLACE):小表可以,大表风险高(row log 溢出、MDL 排队)

无论哪种,执行前必查长事务:

sql 复制代码
SELECT * FROM information_schema.innodb_trx
WHERE TIMESTAMPDIFF(SECOND, trx_started, NOW()) > 60;

因为 DDL 要拿排他 MDL 锁,前面有个长事务就会连锁阻塞所有业务 SQL。

Q28:分库分表怎么选分片键?全局 ID 怎么生成?

分片键选择原则:

  • 选查询频率最高的那个维度(订单一般按 user_id,让单用户查询落在一片)
  • 避免热点(按时间分片会导致新片成为热点)
  • 尽量避免跨片 JOIN 和跨片事务

全局 ID 方案对比:

方案 优点 缺点
数据库号段(segment) 简单、单调递增、可控 有单点,需做好高可用
雪花算法 Snowflake 本地生成、高性能、趋势递增 依赖机器时钟,时钟回拨会出问题
UUID 最简单 无序、占空间、索引性能差
Redis INCR 简单 依赖 Redis 持久化

六、场景题(Q29 - Q30)

Q29:一个表有 (a, b, c) 联合索引,下面几条 SQL 谁走索引?

sql 复制代码
-- 表 t,索引 idx_abc(a,b,c)
SELECT * FROM t WHERE a=1 AND b>2 AND c=3;   -- 用到 a、b;c 用不上(范围后断)
SELECT * FROM t WHERE c=3 AND b=2 AND a=1;   -- ✅ 三个都用上(优化器会重排条件顺序)
SELECT * FROM t WHERE a=1 ORDER BY b, c;     -- ✅ 走索引,且排序免 filesort
SELECT * FROM t WHERE a=1 ORDER BY c;        -- ❌ 用 a,但排序要 filesort(b 缺失)
SELECT * FROM t WHERE b=2 ORDER BY a;        -- ❌ 无 a,走不了索引

关键点 :WHERE 里的条件顺序不影响索引使用(优化器会重排),

但列的"连续性"会影响------断在哪一列,后面的列就用不上了。

Q30:线上发现 CPU 100%,怎么定位?

sql 复制代码
-- 1. 看当前在跑什么
SELECT id, user, host, db, command, time, state, LEFT(info, 120)
FROM information_schema.PROCESSLIST
WHERE command <> 'Sleep' AND time > 5
ORDER BY time DESC;

-- 2. 看哪类 SQL 消耗最多
SELECT DIGEST_TEXT, COUNT_STAR,
       SUM_TIMER_WAIT/1e12 AS total_sec,
       SUM_ROWS_EXAMINED   AS rows_examined
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC LIMIT 5;

-- 3. 在 OS 层确认是哪个线程
top -H -p $(pidof mysqld)
-- 把 OS 线程号对应到 MySQL 内部
SELECT * FROM performance_schema.threads WHERE THREAD_OS_ID = <pid>;

常见原因排序:慢 SQL(全表扫描 / 排序)> 高并发 > 锁等待 > 后台刷脏 。

CPU 100% 第一反应永远是"找那条慢 SQL",而不是加机器。

小结:面试回答的三个层次

层次 表现 例子
第一层 背定义 "索引是 B+ 树"
第二层 讲清为什么 "因为 B+ 树非叶子只存 key,16KB 页能塞上千 key,树高压到 3~4 层"
第三层 讲清取舍和场景 "所以它适合范围和点查;但写多、基数低的列建索引收益不大,反而拖慢写入"

面试官真正在意的不是你记住了多少,而是:

  • 能不能讲清楚"为什么"------每个设计背后都有取舍
  • 有没有踩过坑------说出一个真实事故比背十个定义有用
  • 知不知道边界------"这个方案在XX场景下不适用",这句话非常加分

把这一系列(索引、SQL 优化、事务、锁、日志、备份、参数调优)串起来看,

你会发现 MySQL 的所有设计都围绕一条主线:

用内存换磁盘 IO、用空间换时间、用一致性换可用性 ------而调优的本质,

就是根据你的业务在这三者之间找到那个平衡点。

相关推荐
神仙别闹1 小时前
基于C++实现的贪吃蛇游戏平台
java·c++·游戏
布吉岛的石头1 小时前
Java 程序员第 49 阶段11:Java 接 BERT:用 ONNX Runtime 做句向量推理
java·人工智能·python·深度学习·bert·transformer
染指11101 小时前
140.Agent-多Agent框架-Agent执行Skills流程
数据库·人工智能·设计模式·langchain·agents
niucloud-admin1 小时前
JAVA V6 多商户商城 开发文档——JAVA服务端
java·开发语言
fengkai45451 小时前
十二、Redis -2
运维·数据库·redis·容器
SL_staff1 小时前
设备越多系统越崩?根源在三层抽象失效
spring boot·物联网·github
alexlifexyz1 小时前
写了个 Claude Code 插件:AI 写的 Java 违反阿里规约,就写不进文件
java