【面试】MySQL 面试题(追问)

发布于:2025-09-07 ⋅ 阅读:(20) ⋅ 点赞:(0)

1. 为什么有时候建了索引查询还是慢?

  • 举例SELECT * FROM users WHERE age + 1 = 30;

  • 场景:索引失效,因为对字段做了计算。

  • 解决方法:避免在索引列上做函数或运算,改为 WHERE age = 29

追问链条

  1. 追问:MySQL 索引失效常见有哪些情况?
    回答

    • 对索引列做函数或运算

    • 使用隐式类型转换(int 列用字符串条件)

    • 使用 or 条件,其中部分列无索引

    • like 前导 %

    • 查询范围过大,优化器判断全表扫描更快

  2. 追问:explain 中 rowsfiltered 怎么理解?
    回答rows 是预计扫描的行数,filtered 是过滤后保留的比例。rows * filtered ≈ 实际处理的行数。

  3. 追问:如果索引没生效,你如何排查?
    回答:先用 explain 看执行计划,再 analyze table 更新统计信息,如果优化器仍选错,可以用 force index

2. 什么是索引覆盖查询?为什么更快?

  • 举例SELECT name, age FROM users WHERE id = 100;

  • 场景:联合索引 (id, name, age) 覆盖了查询字段,不用回表。

  • 解决方法:建立覆盖索引,提高查询性能。

追问链条

  1. 追问:explain 结果里 Using index 代表什么?
    回答:表示索引覆盖查询,数据直接从索引里获取,不用回表。

  2. 追问:覆盖索引和普通索引有什么本质区别?
    回答:普通索引需要回表获取数据;覆盖索引存储了查询所需字段,可直接返回结果。

  3. 追问:如果表字段很多,哪些列适合放到覆盖索引?
    回答:经常出现在 where、order by、group by、select 子句里的列,但要控制索引大小,避免过度索引。

3. 为什么 count(*) 很慢?如何优化?

  • 举例SELECT COUNT(*) FROM big_table;

  • 场景:大表全表扫描。

  • 解决方法

    • 使用 Redis 缓存近似值

    • 使用分区表分区统计

    • InnoDB 下 COUNT(主键)COUNT(*) 效果一致

追问链条

  1. 追问:MyISAM 和 InnoDB 的 COUNT(*) 有何区别?
    回答:MyISAM 直接存储了总行数,COUNT(*) 很快;InnoDB 必须逐行扫描,性能差。

  2. 追问:Redis 里存储计数值,如何保证和数据库一致?
    回答:可以通过事务更新时同步更新 Redis;或者异步校正(定时批量刷新)。

  3. 追问:如果必须实时准确统计,你会怎么做?
    回答:用数据库事务内维护计数表,或者利用 binlog 同步到统计系统实时计算。

4. MySQL 中 limit 偏移量大时性能问题

  • 举例SELECT * FROM orders LIMIT 1000000, 20;

  • 场景:偏移量大时,MySQL 仍会扫描前 N 行。

  • 解决方法

    • 使用 WHERE id > ? LIMIT ? 游标翻页

    • 延迟关联优化:先查主键,再 join 回表

追问链条

  1. 追问:什么是延迟关联?
    回答:先用索引查出主键集合,再通过主键 join 原表获取数据,减少扫描。

  2. 追问:MySQL 8.0 窗口函数能优化分页吗?
    回答:可以用 ROW_NUMBER()NTILE() 来分页,但依然受限于排序开销。

  3. 追问:前端无限滚动分页时你会怎么做?
    回答:使用游标分页(基于 id 或时间戳),避免大 offset。

5. explain 执行计划中 type = ALL 意味着什么?

  • 举例EXPLAIN SELECT * FROM users WHERE name = 'Tom';

  • 场景:type=ALL 表示全表扫描。

  • 解决方法:加索引,避免全表扫描。

追问链条

  1. 追问:type 的执行方式从好到差怎么排?
    回答:system > const > eq_ref > ref > range > index > ALL。

  2. 追问:explain 中 possible_keys 和 key 有何区别?
    回答:possible_keys 是可用索引,key 是实际使用索引。

  3. 追问:如果优化器选择了错误索引怎么办?
    回答:可以用 force index 指定索引,或者通过 analyze table 更新统计信息来修正。

6. 为什么 MySQL 有时不走索引而走全表扫描?

  • 举例SELECT * FROM users WHERE name LIKE '%abc';

  • 场景:前导 %,索引失效。

  • 解决方法

    • 改写成 LIKE 'abc%'

    • 建 FULLTEXT 索引

    • 使用外部搜索引擎(ES)

追问链条

  1. 追问:索引失效的其他原因有哪些?
    回答:函数运算、隐式转换、or 未优化、范围查询后索引失效。

  2. 追问:FULLTEXT 索引和普通索引的区别?
    回答:FULLTEXT 用倒排索引存储词项,更适合模糊搜索。

  3. 追问:如果查询条件必须模糊匹配 %abc%,如何优化?
    回答:使用倒排索引(ES)或 trigram 索引,MySQL 自身不适合处理这种场景。

7. 为什么 in 查询过长会变慢?

  • 举例SELECT * FROM users WHERE id IN (1,2,3,...100000);

  • 场景:in 列表过长,优化器难以处理。

  • 解决方法

    • 使用临时表 join

    • 分批查询

追问链条

  1. 追问:in 和 exists 的区别?
    回答:in 先查子查询再匹配,exists 逐行判断子查询结果,优化器会自动转换。

  2. 追问:in 列表多少个元素以内性能还可以?
    回答:一般几百个以内影响不大,几千上万性能就很差。

  3. 追问:如果前端传一个几万 id 的数组怎么办?
    回答:写入临时表,用 join 方式查询,效率更高。

8. join 查询为什么会慢?

  • 举例SELECT * FROM users u JOIN orders o ON u.id=o.user_id;

  • 场景:join 字段没索引,或者两个大表 join。

  • 解决方法

    • 给 join 字段建索引

    • 小表驱动大表

追问链条

  1. 追问:什么是小表驱动大表?
    回答:MySQL 优化器会选择小结果集的表做驱动表,减少循环次数。

  2. 追问:join 的索引建在哪个表?
    回答:建在被驱动表的关联字段上。

  3. 追问:两个 1 亿行大表 join 怎么办?
    回答:分批 join、用中间表存结果,或拆到离线数仓做计算。

9. MySQL 中的回表问题

  • 举例:索引 (id, name),查询 SELECT * FROM users WHERE id=10;

  • 场景:索引不覆盖所有列,需要回表。

  • 解决方法:建覆盖索引,或者只查需要字段。

追问链条

  1. 追问:回表为什么慢?
    回答:需要通过二级索引找到主键,再去主键索引取数据,增加 I/O。

  2. 追问:什么时候可以避免回表?
    回答:使用覆盖索引,或者只查询索引里的列。

  3. 追问:联合索引如何设计避免回表?
    回答:尽量把 where 和 select 用到的列放进索引里。

10. explain 里的 rows 和 filtered 代表什么?

  • 场景:rows 表示预计扫描的行数,filtered 表示过滤比例。

  • 解决方法:关注 rows*filtered,判断优化空间。

追问链条

  1. 追问:rows 值是如何估算的?
    回答:基于索引统计信息,可能不准。

  2. 追问:filtered 小说明什么?
    回答:说明条件过滤效果不好,大量行被丢弃,索引利用率低。

  3. 追问:如何让 rows 和 filtered 更准确?
    回答:执行 analyze table 更新统计信息。

11. MySQL 中的联合索引为什么遵循最左前缀匹配?

  • 举例:索引 (name, age, city),查询 WHERE name='Tom' AND age=20 能用上,但 WHERE age=20 用不了。

  • 场景:索引匹配规则决定了必须从最左边字段开始匹配。

  • 解决方法:建索引时根据查询条件的常用顺序来设计。

  • 追问与回答

    1. :如果查询 WHERE name LIKE 'Tom%',能走索引吗?
      :可以,因为前缀匹配仍然符合最左原则。

    2. :如果查询 WHERE age=20 AND city='BJ',会用索引吗?
      :不会,因为 name 缺失,破坏了最左前缀。

    3. :如何解决这种索引利用率低的问题?
      :可以调整索引顺序,或者用多个单列索引结合 Index Merge。

12. 什么是索引下推优化(Index Condition Pushdown, ICP)?

  • 举例SELECT * FROM users WHERE age > 20 AND name LIKE 'Tom%';

  • 场景:MySQL 5.6+ 会把 age > 20 这样的条件下推到存储引擎层过滤,减少回表次数。

  • 解决方法:升级 MySQL 版本,合理利用 ICP 优化。

  • 追问与回答

    1. :怎么判断查询用了 ICP?
      :执行计划里 Extra 字段会显示 Using index condition

    2. :ICP 在什么情况下没用?
      :当查询列不在索引里时,MySQL 仍需回表。

    3. :ICP 和覆盖索引能一起用吗?
      :可以,但覆盖索引通常比 ICP 更高效。

13. 为什么大批量 insert/update/delete 会导致性能下降?

  • 举例:一次性 DELETE FROM orders WHERE status='closed'; 删除 1000 万行。

  • 场景:大量行锁、redo log、undo log 导致 I/O 压力大。

  • 解决方法

    • 分批操作,每次 1000 或 10000 条

    • 使用 pt-archiver 工具做归档

  • 追问与回答

    1. :大批量删除时如何避免 binlog 太大?
      :分批提交,或者临时关闭 binlog(非主从环境)。

    2. :update 为什么会锁表?
      :当 where 条件缺乏索引,行锁会退化为表锁。

    3. :delete 太慢还能怎么优化?
      :逻辑删除(打标记),配合定期归档。

14. InnoDB 和 MyISAM 的区别?

  • 举例:同样的 SELECT COUNT(*) FROM table;,MyISAM 直接读元数据,InnoDB 需要扫描。

  • 场景:不同引擎适合不同业务。

  • 解决方法:一般使用 InnoDB,因为支持事务和行锁。

  • 追问与回答

    1. :为什么 MySQL 8.0 不再支持 MyISAM?
      :因为缺乏事务、崩溃恢复差,官方逐步弃用。

    2. :什么时候还会用 MyISAM?
      :只读、临时统计类场景(历史上常见,现在少用)。

    3. :如果我需要全文索引怎么办?
      :InnoDB 在 MySQL 5.6+ 也支持全文索引,不必依赖 MyISAM。

15. order by 为什么会触发 filesort?

  • 举例SELECT * FROM users ORDER BY age; 没有 age 索引时。

  • 场景:无法利用索引顺序时,MySQL 需要额外排序。

  • 解决方法

    • 建立合适的索引

    • 避免大数据集排序

  • 追问与回答

    1. :filesort 的单路和双路算法区别?
      :单路算法直接取排序列和查询列,双路需要先排序再回表。

    2. :能否用覆盖索引避免 filesort?
      :可以,只要排序列和 select 列都在索引里。

    3. :group by 和 order by 在执行计划里有啥区别?
      :group by 本质上会隐含排序,除非 group by ... order by null

16. 为什么 join 查询会很慢?

  • 举例SELECT * FROM users u JOIN orders o ON u.id = o.user_id;

  • 场景:大表 join,驱动表和被驱动表选择错误。

  • 解决方法

    • 小表驱动大表

    • 给 join 字段加索引

  • 追问与回答

    1. :什么是小表驱动大表?
      :让行数少的表作为驱动表,减少 join 次数。

    2. :join 时索引建在主表还是从表?
      :一般建在被驱动表(右表)的关联字段。

    3. :两个 1 亿行大表 join 怎么办?
      :先分区/分表,或考虑中间结果写入临时表,再 join。

17. MySQL 如何避免幻读?

  • 举例:事务 A SELECT * FROM users WHERE age > 20;,事务 B 插入一条 age=25,事务 A 再次查询时看到新数据。

  • 场景:幻读问题。

  • 解决方法:InnoDB 在 RR 隔离级别下用 Next-Key Lock 避免幻读。

  • 追问与回答

    1. :RC 隔离级别下会不会有幻读?
      :会,因为只加行锁,不加 gap 锁。

    2. :gap lock 是什么?
      :锁定索引区间,阻止插入。

    3. :MySQL 默认隔离级别是什么?
      :RR(Repeatable Read,可重复读)。

18. 什么是死锁?如何解决?

  • 举例:事务 A 锁住 row1,再等 row2;事务 B 锁住 row2,再等 row1。

  • 场景:多个事务交叉锁定,形成循环依赖。

  • 解决方法

    • 保持一致的加锁顺序

    • 设置事务超时

  • 追问与回答

    1. :InnoDB 如何检测死锁?
      :等待图(Wait-for Graph),发现循环依赖时回滚一个事务。

    2. :怎么避免死锁?
      :固定顺序锁资源、尽量缩短事务时间。

    3. :遇到死锁你会怎么排查?
      :查看 SHOW ENGINE INNODB STATUS\G,分析死锁日志。

19. explain 中 key_len 的含义是什么?

  • 举例EXPLAIN SELECT * FROM users WHERE id=100;key_len=4

  • 场景:表示索引使用的字节数。

  • 解决方法:通过 key_len 可以判断索引是否被完整利用。

  • 追问与回答

    1. :如果 key_len=8,说明什么?
      :用了索引里 8 个字节,比如 BIGINT 类型。

    2. :能否通过 key_len 判断联合索引用到几列?
      :可以,不同列累加。

    3. :possible_keys 和 key 的区别?
      :possible_keys 表示可能用的索引,key 表示实际用的索引。

20. 分区表有哪些使用场景?

  • 举例:日志表 log_2023log_2024 按时间分区。

  • 场景:大表数据按时间或范围划分,提高查询效率。

  • 解决方法:使用 RANGE、LIST、HASH 分区。

  • 追问与回答

    1. :分区表和分表的区别?
      :分区表是逻辑上一个表,物理上多份;分表是多个独立表。

    2. :分区表的限制有哪些?
      :不支持外键,分区键必须出现在所有唯一索引里。

    3. :分区表对 count(*) 有加速吗?
      :如果 where 条件能命中分区,可以减少扫描数据。

21. 大表 alter table 为什么很慢?

  • 举例ALTER TABLE users ADD COLUMN age INT; 在亿级表上执行。

  • 场景:需要复制表结构和数据,阻塞 DML。

  • 解决方法

    • 使用 Online DDL(MySQL 5.6+ 支持)

    • 使用 pt-online-schema-change 工具

  • 追问与回答

    1. :什么是 Online DDL?
      :DDL 执行期间允许读写,避免长时间锁表。

    2. :MySQL 哪些 alter 操作支持 Online DDL?
      :如新增列、创建索引,多数支持,但删除列不支持。

    3. :不停机情况下如何加索引?
      :使用 Online DDL 或 pt-online-schema-change。

22. 主从复制延迟的原因?

  • 举例:主库写入压力大,从库同步延迟。

  • 场景:高并发写操作导致延迟。

  • 解决方法

    • 使用半同步复制

    • 增加从库,提高并行复制能力

  • 追问与回答

    1. :MySQL 5.7 的并行复制怎么实现的?
      :按库并行,8.0 支持按事务组并行。

    2. :如何监控复制延迟?
      SHOW SLAVE STATUS 里的 Seconds_Behind_Master

    3. :如何减少延迟?
      :优化主库写入,或使用多线程复制。

23. 如何优化 select * 查询?

  • 举例SELECT * FROM users;

  • 场景:会扫描所有字段,增加 I/O。

  • 解决方法:只取必要字段,使用覆盖索引。

  • 追问与回答

    1. :为什么 select * 慢?
      :返回多余字段,可能导致回表。

    2. :select * 对于 ORM 框架有什么影响?
      :容易加载过多数据,导致 N+1 问题。

    3. :什么时候 select * 可以接受?
      :临时调试,或小表查询。

24. delete 和 truncate 的区别?

  • 举例DELETE FROM users; vs TRUNCATE TABLE users;

  • 场景:清空表数据的两种方式。

  • 解决方法:按需选择。

  • 追问与回答

    1. :delete 会触发事务和触发器吗?
      :会;truncate 不会。

    2. :truncate 会释放空间吗?
      :会重置自增 ID 并释放空间。

    3. :在 binlog 里,delete 和 truncate 有什么区别?
      :delete 逐行记录,truncate 是 DDL。

25. 事务中的脏读、不可重复读和幻读的区别?

  • 举例

    • 脏读:读到未提交数据

    • 不可重复读:前后两次读结果不同

    • 幻读:前后两次读,行数不同

  • 场景:事务并发读写导致问题。

  • 解决方法:通过不同隔离级别控制。

  • 追问与回答

    1. :MySQL 默认隔离级别能避免哪几种?
      :RR 能避免脏读、不可重复读,避免大多数幻读。

    2. :哪种隔离级别性能最好?
      :READ UNCOMMITTED,几乎无加锁,但问题最多。

    3. :Serializable 怎么实现的?
      :强制所有事务串行执行,锁粒度最大。

26. MySQL 为什么建议使用自增主键?

  • 举例CREATE TABLE orders (id BIGINT AUTO_INCREMENT PRIMARY KEY, ...);

  • 场景:自增主键能保证数据有序插入,减少页分裂。

  • 解决方法:推荐使用自增主键,避免业务字段作为主键。

  • 追问与回答

    1. :UUID 做主键会有什么问题?
      :UUID 无序,插入会导致页分裂、随机 I/O。

    2. :主键为什么建议用 BIGINT?
      :可支持更大范围,避免自增 ID 溢出。

    3. :是否适合用雪花算法替代自增 ID?
      :可以,但要保证有序性,否则索引性能会下降。

27. 为什么不要在 where 条件中对列使用函数?

  • 举例WHERE DATE(create_time) = '2023-09-01';

  • 场景:会导致索引失效。

  • 解决方法:改为 WHERE create_time >= '2023-09-01' AND create_time < '2023-09-02'

  • 追问与回答

    1. WHERE YEAR(create_time)=2023 为什么不走索引?
      :因为索引存的是完整字段值,函数破坏了匹配。

    2. :能否通过函数索引解决?
      :MySQL 8.0+ 支持函数索引,可以优化。

    3. :如果不能修改 SQL,怎么办?
      :可以通过生成列(Generated Column)+ 索引。

28. 为什么说 select count(1) 和 count(*) 性能差不多?

  • 举例SELECT COUNT(*) FROM users; vs SELECT COUNT(1) FROM users;

  • 场景:MySQL 内部优化后,两者几乎一样。

  • 解决方法:统一使用 count(*),语义更清晰。

  • 追问与回答

    1. :count(column) 和 count() 有什么区别?
      :count(column) 会忽略 NULL,count(
      ) 会统计所有行。

    2. :InnoDB 的 count(*) 为什么慢?
      :没有存储总行数,需要扫描。

    3. :如果只要近似值怎么办?
      :用 show table status 或 Redis 计数器。

29. 为什么 MySQL 的 like '%abc' 不能走索引?

  • 举例WHERE name LIKE '%Tom'

  • 场景:前缀不确定,B+Tree 无法利用索引。

  • 解决方法

    • LIKE 'Tom%' 可以走索引

    • 使用全文索引或 ES

  • 追问与回答

    1. LIKE 'Tom%' 为什么能用索引?
      :因为前缀确定,可以从索引树定位。

    2. :InnoDB 支持全文索引吗?
      :支持,5.6+ 开始提供。

    3. :大规模模糊搜索怎么办?
      :考虑 Elasticsearch 等搜索引擎。

30. 如何优化慢查询?

  • 举例:某查询 SELECT * FROM orders WHERE user_id=123 AND status='done'; 执行 10 秒。

  • 场景:索引缺失或执行计划不佳。

  • 解决方法

    • 开启慢查询日志

    • 用 explain 分析

    • 调整索引或 SQL

  • 追问与回答

    1. :如何开启慢查询日志?
      SET GLOBAL slow_query_log=1;

    2. :explain 中 rows=1000000 说明什么?
      :预估扫描行数大,说明索引不合适。

    3. :如果索引优化后仍慢,怎么办?
      :考虑缓存、分库分表或改用 ES。

31. 为什么 in 查询比 join 慢?

  • 举例WHERE id IN (SELECT id FROM ...)

  • 场景:in 可能导致子查询重复执行。

  • 解决方法:改写为 join 或 exists。

  • 追问与回答

    1. :in 和 exists 的区别?
      :in 适合小表驱动大表,exists 适合大表驱动小表。

    2. :优化器会自动把 in 转为 join 吗?
      :有时会,但不稳定。

    3. :什么时候 in 更优?
      :当 in 集合较小、且有索引时。

32. 为什么 update 会锁全表?

  • 举例UPDATE users SET age=20 WHERE name LIKE '%Tom%';

  • 场景:where 条件没用索引,锁退化为表锁。

  • 解决方法:加索引,避免无索引更新。

  • 追问与回答

    1. :InnoDB 默认是行锁还是表锁?
      :行锁,但缺乏索引时会退化为表锁。

    2. :delete 会不会全表锁?
      :同理,如果没有索引,会锁全表。

    3. :如何避免大范围锁表?
      :加索引,或分批更新。

33. 为什么 MySQL 不建议使用外键?

  • 举例ALTER TABLE orders ADD CONSTRAINT fk_user FOREIGN KEY(user_id) REFERENCES users(id);

  • 场景:外键会导致写操作性能下降,难以分库分表。

  • 解决方法:应用层维护约束,避免外键。

  • 追问与回答

    1. :外键的优点是什么?
      :保证数据一致性。

    2. :外键约束能不能优化性能?
      :不能,反而增加额外校验。

    3. :如果不用外键,怎么保证一致性?
      :在应用层保证,比如写入时校验。

34. binlog 有几种格式?区别是什么?

  • 举例:STATEMENT、ROW、MIXED 三种模式。

  • 场景:不同格式影响复制和性能。

  • 解决方法:多数情况下用 ROW 模式。

  • 追问与回答

    1. :ROW 格式的优缺点?
      :优点是可靠,缺点是日志量大。

    2. :STATEMENT 格式的风险?
      :非确定性函数(如 now())可能导致不一致。

    3. :MIXED 格式什么时候用?
      :特殊情况会自动切换,如使用函数时。

35. MySQL 的 redo log 和 binlog 有什么区别?

  • 举例:redo log 是物理日志,binlog 是逻辑日志。

  • 场景:redo 保证 crash-safe,binlog 保证主从一致。

  • 解决方法:两者结合才能保证事务安全。

  • 追问与回答

    1. :redo log 写完但 binlog 没写完,会怎样?
      :可能导致主从不一致。

    2. :binlog 主要用来做什么?
      :主从复制、数据恢复。

    3. :redo log 循环写满会发生什么?
      :会阻塞写入,直到 checkpoint 推进。

36. MySQL 的 undo log 有什么作用?

  • 举例:执行 UPDATE users SET age=30 WHERE id=1;,undo log 保存原值 20。

  • 场景:用于事务回滚和 MVCC。

  • 解决方法:合理控制长事务,避免 undo 堆积。

  • 追问与回答

    1. :undo log 存放在哪里?
      :存放在回滚段,表空间里。

    2. :MVCC 为什么依赖 undo log?
      :读取历史版本需要从 undo log 里获取。

    3. :undo log 会不会被清理?
      :提交后可清理,长事务可能导致堆积。

37. 为什么不建议大事务?

  • 举例:一次性更新 100 万行。

  • 场景:大事务会占用大量锁和日志空间。

  • 解决方法:拆分事务,分批提交。

  • 追问与回答

    1. :大事务对 binlog 有什么影响?
      :产生超大 binlog,可能导致同步延迟。

    2. :大事务对锁的影响?
      :持锁时间长,容易引发阻塞和死锁。

    3. :如何避免?
      :分批提交,每批 1000 或 10000 行。

38. 为什么 count(distinct col) 很慢?

  • 举例SELECT COUNT(DISTINCT user_id) FROM orders;

  • 场景:需要排序去重,性能差。

  • 解决方法:使用临时表、分组统计,或借助数据仓库。

  • 追问与回答

    1. :count(distinct col1, col2) 怎么优化?
      :可以拼接成 concat(col1, col2),再 distinct。

    2. :能否用 group by 替代 distinct?
      :可以,有时更快。

    3. :如果数据量很大?
      :可以用 Spark/Hive 计算。

39. group by 为什么会用临时表?

  • 举例SELECT city, COUNT(*) FROM users GROUP BY city;

  • 场景:当没有合适索引时,需要额外排序或临时表。

  • 解决方法:在 group by 列上建索引。

  • 追问与回答

    1. :group by 默认会排序吗?
      :会,可以用 ORDER BY NULL 禁止。

    2. :extra 里出现 Using temporary,说明什么?
      :说明用了临时表,效率低。

    3. :怎么优化 group by?
      :索引覆盖,或分批汇总。

40. MySQL 的临时表分为哪几种?

  • 举例:内存临时表、磁盘临时表。

  • 场景:order by/group by 超出内存限制会用磁盘临时表。

  • 解决方法:调整 tmp_table_size、max_heap_table_size。

  • 追问与回答

    1. :怎么判断用了磁盘临时表?
      Created_tmp_disk_tables 监控指标升高。

    2. :临时表会不会影响性能?
      :会,尤其是大查询。

    3. :如何减少临时表?
      :加索引,避免 select *。

41. MySQL 的行锁是怎么实现的?

  • 举例SELECT * FROM users WHERE id=1 FOR UPDATE;

  • 场景:通过索引项加锁。

  • 解决方法:尽量走索引,避免表锁。

  • 追问与回答

    1. :行锁是加在记录上还是索引上?
      :加在索引项上。

    2. :如果没有索引条件,会怎样?
      :会退化为表锁。

    3. :怎么避免锁升级?
      :使用合理索引,避免范围过大。

42. 什么是间隙锁(gap lock)?

  • 举例SELECT * FROM users WHERE age BETWEEN 20 AND 30 FOR UPDATE;

  • 场景:会锁定区间,阻止插入。

  • 解决方法:减少范围锁,尽量用等值条件。

  • 追问与回答

    1. :gap lock 是为了避免什么?
      :避免幻读。

    2. :在 RC 隔离级别下有 gap lock 吗?
      :没有,只有 RR 下有。

    3. :gap lock 会不会影响并发?
      :会,范围越大并发越差。

43. MySQL 的 change buffer 是什么?

  • 举例:非唯一二级索引更新时,写入 change buffer,异步合并。

  • 场景:减少磁盘 I/O。

  • 解决方法:合理开启 innodb_change_buffering。

  • 追问与回答

    1. :哪些情况会用 change buffer?
      :更新非唯一二级索引。

    2. :唯一索引会走 change buffer 吗?
      :不会,因为必须立即校验唯一性。

    3. :什么时候合并 change buffer?
      :后台线程或查询索引页时。

44. MySQL 的 buffer pool 有什么作用?

  • 举例:buffer pool 缓存数据页和索引页。

  • 场景:减少磁盘 I/O。

  • 解决方法:合理配置 innodb_buffer_pool_size。

  • 追问与回答

    1. :buffer pool 一般设多少?
      :推荐 60%~80% 内存。

    2. :怎么查看命中率?
      :通过 SHOW ENGINE INNODB STATUS

    3. :buffer pool 太小会怎样?
      :频繁淘汰页,性能下降。

45. MySQL 的 doublewrite buffer 有什么用?

  • 举例:数据页写入时,先写 doublewrite,再写数据文件。

  • 场景:防止部分写失败导致页损坏。

  • 解决方法:保持开启 doublewrite。

  • 追问与回答

    1. :doublewrite 是写两次吗?
      :是,先写 2MB buffer,再刷盘。

    2. :能关闭吗?
      :能,但风险大。

    3. :影响性能吗?
      :几乎无明显影响,因为是顺序写。

46. MySQL 的 redo log 是循环写的吗?

  • 举例:redo log 文件组,固定大小,循环覆盖。

  • 场景:保证写入性能。

  • 解决方法:合理设置 innodb_log_file_size。

  • 追问与回答

    1. :如果写满会怎样?
      :会阻塞写操作,等待 checkpoint。

    2. :checkpoint 的作用是什么?
      :把脏页刷盘,推进日志。

    3. :redo log 和 undo log 的区别?
      :redo 用于恢复,undo 用于回滚。

47. MySQL 的主键索引和二级索引有什么区别?

  • 举例:主键索引存储完整数据,二级索引存储主键。

  • 场景:二级索引需要回表。

  • 解决方法:合理利用覆盖索引。

  • 追问与回答

    1. :回表是什么意思?
      :二级索引定位到主键,再回到主键索引取数据。

    2. :为什么主键索引是聚簇索引?
      :数据按主键顺序存储。

    3. :二级索引能避免回表吗?
      :可以,靠覆盖索引。

48. 为什么大表查询建议分区?

  • 举例:分区表按日期拆分。

  • 场景:避免全表扫描。

  • 解决方法:合理设计分区键。

  • 追问与回答

    1. :分区表和分库分表区别?
      :分区是逻辑拆分,底层仍在一个实例。

    2. :分区表有什么限制?
      :不支持外键,某些 SQL 也有限制。

    3. :什么时候不用分区?
      :小表或随机访问为主时。

49. MySQL 为什么要有自适应哈希索引?

  • 举例:热点范围查询多时,会自动生成哈希索引。

  • 场景:提高热点访问性能。

  • 解决方法:保持默认开启。

  • 追问与回答

    1. :哈希索引和 B+Tree 索引区别?
      :哈希索引适合等值查找,不适合范围。

    2. :自适应哈希索引会不会影响写?
      :会,维护开销增加。

    3. :能关闭吗?
      :可以,通过 innodb_adaptive_hash_index。

50. 为什么要控制表字段数量?

  • 举例:单表 200 列,查询效率很差。

  • 场景:字段过多,行大小超限,导致溢出存储。

  • 解决方法:字段拆分,避免过宽表。

  • 追问与回答

    1. :MySQL 一行最大多大?
      :InnoDB 约 8KB,超过会用溢出页。

    2. :TEXT、BLOB 存储有什么特殊性?
      :只存指针,数据放溢出页。

    3. :宽表有什么坏处?
      :行长大,缓存命中率低,I/O 成本高。


网站公告

今日签到

点亮在社区的每一天
去签到