【面试题】1. MVCC 到底是怎么实现"读不阻塞写、写不阻塞读"的?核心机制是什么?
【标准答案】MVCC 靠两个东西:undo log 版本链和 ReadView。每行数据有隐藏字段 trx_id(最后修改的事务 ID)和 roll_pointer(指向上一个版本的 undo log)。更新不覆盖原数据,而是写新版本,旧版本挂 undo log 链上。读的时候根据 ReadView 决定能看到哪个版本——ReadView 记录当前活跃事务列表,如果行的 trx_id 在你开始读之后才提交,你就看不到它,顺着 undo 链找上一个可见版本就行。RC 隔离级别每次读都生成新 ReadView,RR 级别复用第一次读的 ReadView。一句话:用空间换并发,旧版本不删,读永远有路走。
【面试题】2. MySQL 生产环境参数调优,你最优先动哪几个参数?为什么?
【标准答案】优先动五个:一、innodb_buffer_pool_size,设为物理内存的 60%-70%,这是 InnoDB 的命根子,数据和索引都缓存在这,设小了磁盘 IO 扛不住。二、innodb_log_file_size,一般设 1-2G,日志文件太小 checkpoint 频繁刷脏页,IO 抖动。三、innodb_flush_log_at_trx_commit,默认 1 最安全但最慢,对性能敏感的业务设 2(每秒刷)但接受宕机丢一秒数据。四、sync_binlog,默认 1,高并发可设 0 或 N 降低刷盘频率。五、max_connections,别盲目放大,连接太多线程切换开销反而拖垮,500-1000 够用配合连接池。调优原则:先保证数据安全,再逐步放开性能参数。
【面试题】3. PostgreSQL 相比 MySQL 有哪些独有优势?什么场景你会弃 MySQL 选 PG?
【标准答案】PG 三个杀手锏:一、对复杂查询的支持碾压 MySQL,窗口函数、CTE、递归查询、LATERAL JOIN 都更成熟,分析型业务首选。二、扩展性极强,支持自定义类型、操作符、函数语言(Python/R/JS 都能写存储过程),PostGIS 做地理计算是行业标准。三、MVCC 实现更干净,没有 undo log,旧版本就在表里,不需要回滚段,长事务不会导致 undo 膨胀。什么时候选 PG:有复杂地理数据分析、需要强 SQL 标准的 OLTP+OLAP 混合场景、团队接受社区生态。什么时候不选:公司 MySQL 积累深厚、需要有收费的商业支持(PG 纯社区),那还是 MySQL 省心。
【面试题】4. Doris 凭什么能做到秒级的大表聚合查询?它的核心架构是怎样的?
【标准答案】Doris 是 MPP 架构,分 Frontend(FE)和 Backend(BE)。FE 负责元管理和查询解析,BE 负责实际存储和计算。核心是第一,真正的列式存储 + 智能索引:数据按列存,查询只读涉及的列,配合前缀索引和 Bloom Filter 过滤掉大部分数据。第二,物化视图(Rollup):预聚合不同维度的数据,聚合查询直接扫预计算结果,效果类似于"提前把账算好"。第三,向量化引擎:一次处理一批数据而不是一行,充分榨干 CPU。第四,高效的分布式聚合:每个 BE 先在本地做初步聚合,结果集很小再汇总到 FE。一句话:列存 + 预聚合 + 向量化 + 分两级聚合,四个优化叠加才做得到秒级。
【面试题】5. 生产环境调优的基本思路是什么?拿到一个新系统你会怎么下手?
【标准答案】三板斧:监控先行、找瓶颈、渐进式调。第一,先把监控搭全——慢查询日志、QPS/连接数/缓存命中率/磁盘 IO 延迟/从库延迟,没监控就是瞎子。第二,找到真正的瓶颈,用 pt-query-digest 分析慢日志,找到 top 慢 SQL,不是凭感觉或者百度参数。第三,逐项优化:先动 SQL 和索引,效果立竿见影;再调 buffer pool 等内存参数;最后动连接数、线程、IO 相关参数。每次只改一项参数,观察效果再改下一个,绝不允许一次改十项不知道哪个生效。第四,做压测验证,不要上完就下班。原则就仨字:可追溯。任何一个改动都得知道为什么改、改完效果如何。
【面试题】6. 一个项目从 0 到 1,数据库架构你会怎么规划?按什么步骤来?
【标准答案】五步走:第一步,搞清业务,用 Excel 画出核心实体和关系,明确读写 QPS、数据量增长预期。第二步,选型——OLTP 默认 MySQL/PG,纯分析考虑 ClickHouse/Doris,全文搜索上 ES,缓存 Redis。第三步,表设计,精雕核心表结构:字段类型选最小够用的、索引提前规划(但不要一开始全加满)、主键用自增还是雪花 ID 想清楚。第四步,预留扩展点:冷热分离策略、分库分表的分片 key 提前定、读写分离的切换方案。第五步,上线前做数据迁移和回滚方案。核心原则:先跑起来再优化,别一上来就搞分布式——单体 MySQL 扛 5000 QPS 完全没问题,过早优化是万恶之源。
【面试题】7. MySQL 的四种隔离级别分别解决什么问题?RR 级别真的能完全避免幻读吗?
【标准答案】读未提交:啥也不管,脏读幻读不可重复读全有。读已提交:解决脏读,但同一事务内两次读可能结果不同(不可重复读)。可重复读:解决不可重复读,通过 MVCC 保证同一事务内读到的数据一致。串行化:全加锁,解决一切并发问题但性能最差。重点来了——RR 级别在快照读(普通 SELECT)下确实没有幻读,因为 MVCC 用同一个 ReadView。但是!当前读(SELECT ... FOR UPDATE/LOCK IN SHARE MODE)下幻读仍然可能发生。InnoDB 用间隙锁来解决当前读的幻读。面试官最喜欢追问这个点,你得区分快照读和当前读的区别。
【面试题】8. 线上发生了死锁,你怎么快速定位和解决?怎么从日志里找到死锁原因?
【标准答案】MySQL 检测到死锁会自动回滚其中一个事务,所以关键是找到原因避免再次发生。定位三步走:一、开启死锁日志记录,innodb_print_all_deadlocks=ON,每次死锁都会打印到 error log。二、用 SHOW ENGINE INNODB STATUS 查看 LATEST DETECTED DEADLOCK 段落,里面有完整的死锁信息——哪些事务、持有哪些锁、等待哪些锁、最后回滚了谁。三、从日志逆推执行顺序:看两个事务分别对哪些索引加锁、加锁顺序是什么。绝大多数死锁的根因是加锁顺序不一致,或者一个事务同时持有共享锁又想要排他锁。解决方向:统一业务代码里的加锁访问顺序、缩小事务范围、降到 RC 级别取消间隙锁。
【面试题】9. RDB 和 AOF 两种持久化方式各有什么优劣?生产环境你会怎么配置?
【标准答案】RDB 是快照,隔一段时间把内存数据全量写入磁盘,文件小、恢复快,但两次快照之间宕机会丢数据。AOF 是写日志,每条写命令都追加到文件,最多丢一秒(everysec),更安全但文件大恢复慢。生产上我不会二选一,而是两个都开:RDB 做灾难恢复兜底,AOF 保证数据不丢。关键参数:appendonly yes,appendfsync everysec,同时打开 aof-use-rdb-preamble 混合模式——重写 AOF 时前半段用 RDB 快照格式、后半段写增量命令,兼顾了恢复速度和数据安全性。Redis 7.0 后混合模式已经是默认了。一句话:RDB 保效率,AOF 保安全,混搭是标准答案。
【面试题】10. 分布式事务有哪些落地方案?TCC、Saga、XA 怎么选?
【标准答案】三种方案适用的场景完全不同。XA/2PC:传统两阶段提交,强一致但性能差,协调者单点,适合数据库层面的跨库事务(比如一次操作要同时写订单库和库存库),小数据量场景用。TCC(Try-Confirm-Cancel):把业务分成预留、确认、取消三个阶段,性能好不锁资源,但代码侵入性强,适合对一致性要求高的扣款扣库存场景,每个操作都要写 confirm 和 cancel 逻辑。Saga:长事务拆成多个本地事务,失败时逆序补偿,适合微服务间长业务流程(比如下单→扣库存→减优惠券→扣积分),异步解耦,最终一致。我的选择逻辑:涉及金额用 TCC,跨服务长流程用 Saga,同数据库多表直接用本地事务,千万别什么东西都上分布式事务。