深蓝黑背景封面:左侧大标题「数据库变慢,别上来就加机器」,副标题「从慢查询到架构层的分层排查顺序」;右侧原创示意——一座五层阶梯自下而上标注慢查询、SQL、索引、表结构、架构,阶梯顶端一面小旗;左上标注「面试经典 · 数据库」,右上标注「Day 04 · 10-22」 图 1:本文封面,五层阶梯就是排查的行进路线。

先说明属性:这是一篇经典题解析,题目出自本地历史面试资料,与任何公司的当前招聘无关。「数据库优化的思路」是开放题里的经典,也是区分「背过答案」和「干过活」的试金石:背答案的人会罗列手段,干过活的人会给顺序。本文的主线就是这个顺序——自下而上五层,能用下一层解决就不上一层,因为越往上动得越狠、代价越大。

第一层:慢查询发现——先找到元凶,再谈优化。

一切优化的前提是知道谁在慢。MySQL 的慢查询日志就是干这个的:执行时间超过 long_query_time 阈值(默认 10 秒,生产一般调低到几百毫秒)且扫描行数达标的语句会被记录下来。两个细节值得记住:慢查询日志默认是关闭的,线上排查第一步是确认它开着;日志里每条语句带执行时间、锁等待时间、扫描行数、返回行数等字段,用官方自带的 mysqldumpslow 可以按次数与耗时聚合排序,「执行次数 × 单次耗时」最高的那几条就是元凶。还可以打开 log_queries_not_using_indexes,把没用索引的查询也抓出来。

第二层:SQL 层——写法问题最便宜,先改。

拿到元凶 SQL,先用执行计划(EXPLAIN)看它走了什么访问路径:全表扫描还是索引、用了哪个索引、扫描行数估算是多少。常见的写法问题包括 SELECT 星号取回根本不需要的列、对索引列套函数导致索引失效、深分页(LIMIT 十万 offset)越翻越慢。这一层的改动不动表结构、不动架构,成本最低,收益却往往立竿见影。

第三层:索引层——为高频条件设计,而不是见列就建。

SQL 写法没问题还慢,轮到索引。为高频查询条件建联合索引,顺序按区分度与最左前缀匹配设计;能用覆盖索引就让查询不回表。但索引不是免费的:每个索引都是一棵要维护的 B+ 树,写入时同步更新,索引越多写放大越严重——给一张写多读少的表堆十个索引,是把读的快换成写的慢。

第四层:表结构层——动 schema 要慎重。

字段类型收紧(能用 INT 不用 VARCHAR)、冷热数据分离(历史数据归档到冷库)、大表按业务维度拆分,都属于这一层。改动涉及数据迁移,风险与成本高,所以排在索引之后。

第五层:架构层——读写分离、缓存、分库分表。

单机优化到头了才考虑架构手术:读多写少上加缓存挡读、读写分离分担主库压力;单机容量到顶再分库分表。这一层引入分布式复杂度——缓存一致性、跨库查询、分布式事务,每一个都是新的问题域。上来就喊分库分表的答案,等于还没查血就开刀。

用 SQL 把第一层落到手上。

以 MySQL 8.4 为例,开启与分析慢查询的标准动作如下:

-- 运行时开启慢查询日志并下调阈值(默认 10 秒太长)
SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 0.5;
-- 把没用索引的查询也记入日志
SET GLOBAL log_queries_not_using_indexes = 1;

-- 拿到元凶 SQL 后看执行计划:关注 type(访问类型)、key(实际走的索引)、rows(估算扫描行数)
EXPLAIN SELECT order_id, amount
FROM orders
WHERE user_id = 10086 AND status = 'PAID'
ORDER BY created_at DESC
LIMIT 20;

执行计划里 type 出现 ALL 意味着全表扫描,rows 估算几十万而实际只取 20 行,这就是索引层的活儿了。慢日志文件用 mysqldumpslow 汇总:mysqldumpslow -s t -t 10 按总耗时排出前十个元凶。

分层方法论图:自下而上五层——第一层慢查询发现,开慢查询日志设定阈值,按执行次数与耗时排序找到元凶 SQL;第二层 SQL 层,用执行计划看这条 SQL 走了什么访问路径,改掉 SELECT 星号、函数包裹索引列、深分页这类写法问题;第三层索引层,为高频条件建联合索引、用覆盖索引免回表,注意索引不是越多越好,写放大要计入成本;第四层表结构层,字段类型收紧、冷热分离、大表归档;第五层架构层,读写分离、缓存挡读、分库分表,这层动手术最大、留到最后。右侧竖向标尺标注:越往下成本越低、越往上动得越狠——顺序是自下而上,能用下一层解决就不上一层。底部提示:每一层动手前先量化基线,改完用同一指标复测 图 2:五层排查顺序与「先量化基线」的操作纪律。

可能的追问与易错点。

「每层怎么验证有效?」固定一个指标——元凶 SQL 的响应时间与扫描行数——动手前记录基线,改完用同一指标复测,没有复测的优化等于没做。易错点三个:上来就加机器或分库分表,跳过便宜的四层;索引见列就建,写放大反噬写入性能;凭感觉判断瓶颈,不开慢查询日志直接动手。

回到面试现场,建议的答题结构:先给「自下而上五层」的顺序总纲,再逐层各讲两三个代表手段,最后强调基线量化与复测纪律——顺序感就是这道题的分水岭。这套顺序对 AI 应用的特征库与会话库同样适用:它们进入中后期最常见的瓶颈就是慢查询,先开日志定位再谈扩容,能省下一大笔冤枉钱。你排查过的最棘手的数据库变慢,最后卡在哪一层?欢迎分享。