1. 什么时候应该考虑给表加索引
很多人一遇到MySQL查询变慢,第一反应就是“给表加索引”。我做了这么多年数据库优化,可以负责任地告诉你:这个方向是对的,但加索引不是万能药,更不是随便拿个字段建个索引就能解决问题。要搞清楚mysql表添加索引到底该怎么做,先得弄明白“什么时候真的需要加索引”。
1.1 慢查询是最直接的信号
如果你发现某个接口的响应时间从原来的几十毫秒涨到了几百毫秒甚至几秒,第一件事不是去加索引,而是先把那几条慢SQL抓出来。MySQL提供了慢查询日志,默认是关着的,你可以先打开:
sql复制-- 查看当前慢查询设置
SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'long_query_time';
-- 开启慢查询日志(也可以写到my.cnf里永久生效)
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1; -- 超过1秒的记录
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
这里我习惯把long_query_time设为1秒,线上环境其实建议设到0.5秒甚至更低。因为现在很多业务对接口响应要求就是百毫秒级,1秒才记录的阈值太宽松了,等你能从慢日志里发现问题的时候,用户早就投诉了。
1.2 怎么看一条SQL是不是缺索引
用EXPLAIN就能看个大概。这是加索引前必须做的一步,千万不能省。我见过太多人上来就直接ALTER TABLE ADD INDEX,结果建完索引查询还是慢,最后发现压根不是索引的问题。
sql复制EXPLAIN SELECT * FROM orders WHERE user_id = 123 AND status = 1;
看type字段,如果出现ALL,说明是全表扫描,这就是需要加索引的信号。如果出现ref、range、const这些,说明索引用得还算正常。但这不是绝对的,我后面会详细说各种情况。
1.3 数据量增长带来的性能拐点
还有一个信号特别容易被忽略:数据量还没到一定程度,索引的作用体现不出来。一张表只有几百行数据,加不加索引区别真的不大,MySQL优化器可能直接选全表扫描还更快。但当数据量涨到几十万、上百万行,全表扫描的代价就完全不一样了。
以我的经验,单表数据量在10万行以内,很多查询其实全表扫描也能扛住。到了100万行往上,没有索引的查询基本就会开始出现明显的延迟,这时候mysql表添加索引的收益最大。但也不是说数据量小就不需要索引,还要考虑查询频率——就算表里只有1万行,一秒被查几百次的接口,加索引也能显著降低数据库压力。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 添加索引前的准备工作
真正动手加索引之前,我强烈建议你先花一点时间把下面几件事搞清楚。这一步做得好,后面能省好多事。
2.1 确认哪条SQL是真正的问题源
不要凭感觉猜,直接在慢日志里找。你也可以用performance_schema来统计一下哪些SQL消耗的资源最多:
sql复制-- 查看当前正在执行的SQL
SHOW PROCESSLIST;
-- 查看执行次数多、耗时长的SQL(需要开启performance_schema)
SELECT DIGEST_TEXT, COUNT_STAR, AVG_TIMER_WAIT
FROM performance_schema.events_statements_summary_by_digest
ORDER BY AVG_TIMER_WAIT DESC
LIMIT 10;
这一步的目的是搞清楚:到底是哪条SQL慢?它慢是因为表没索引,还是因为SQL写得太烂(比如SELECT了不需要的字段、JOIN了无用的大表),又或者是锁等待、网络延迟、硬件瓶颈?索引只能解决“全表扫描”这一类问题,其他问题你加了索引也是白搭。
2.2 用EXPLAIN分析执行计划
拿到目标SQL之后,跑一遍EXPLAIN,重点看这几个字段:
| 字段 | 含义 | 关注点 |
|---|---|---|
| type | 访问类型 | ALL(全表扫)、index(全索引扫)要警惕 |
| key | 实际使用的索引 | NULL说明没用索引 |
| rows | 预估扫描行数 | 数值越大,性能通常越差 |
