MySQL 慢查询优化实战指南
时间:2026-11-14 07:23 作者:emer 分类: 无
MySQL 慢查询优化实战指南
一、先定位慢在哪
数据库变慢不能靠猜,第一步是打开慢查询日志,把执行时间超过阈值的 SQL 记录下来:
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1; -- 超过1秒记录
SHOW VARIABLES LIKE 'slow_query_log_file';
再用 EXPLAIN 分析目标 SQL,重点看 type、key、rows、Extra 四列:type 出现 ALL 表示全表扫描,key 为 NULL 说明没走索引,rows 预估扫描行数过大,Extra 出现 Using filesort、Using temporary 都是危险信号。
二、索引优化是核心
1. 给高频查询字段建索引
ALTER TABLE order_table ADD INDEX idx_uid_status (user_id, status);
联合索引遵循最左前缀,查询条件从左到右匹配,跳过中间列后面的列就用不上。
2. 避免索引失效
- 对索引列做函数、运算:
WHERE DATE(create_time) = '2026-01-01'会失效,改成范围比较; - 隐式类型转换:字符串字段用数字查询会导致索引失效;
LIKE '%xxx'前置百分号无法走索引;OR连接的字段有一个无索引,整体失效;!=、NOT IN往往不走索引。
三、改写低效 SQL
小结果集驱动大表
-- 反例:先扫大表再关联
SELECT * FROM a JOIN b ON a.id = b.a_id WHERE b.type = 1;
-- 优化:先过滤小表,再关联
SELECT a.* FROM (SELECT id FROM b WHERE type = 1 LIMIT 100) t JOIN a ON a.id = t.a_id;
分页深翻页优化
LIMIT 100000, 20 会扫描十万行再丢弃,改用主键游标:
SELECT * FROM order_table WHERE id > 100000 ORDER BY id LIMIT 20;
禁止 SELECT *
只查需要的列,减少回表和网络传输,覆盖索引还能避免回表。
四、表结构与配置优化
- 大字段(TEXT、BLOB)拆到副表,主表只存常用字段;
- 避免过度索引,索引越多写入越慢,删无用索引;
- 合理使用覆盖索引,查询列都在索引里就不用回表;
- 调整 buffer_pool_size,一般设为物理内存的 50%~70%;
- 慢 SQL 配合业务加缓存,把读压力转移到 Redis。
五、压测与验证
用 EXPLAIN ANALYZE 看真实执行计划,优化前后对比扫描行数和耗时。上线前用慢日志复刻 SQL 在测试库压测,避免只在小表上验证就以为有效。
六、常见误区
- 盲目给每个字段加索引,拖慢写入;
- 建了联合索引却从非最左列查询,以为没生效;
- 只看执行时间不看 EXPLAIN,误判瓶颈;
- 深分页一直 LIMIT 偏移量,越翻越慢;
- 数据库扛不住就堆硬件,忽略索引和 SQL 本身的问题。
七、总结
慢查询优化链路:开慢日志定位、EXPLAIN 找问题、补索引并避开失效场景、改写 SQL 减小扫描范围、配合表结构和缓存。优化的本质是减少扫描行数和回表次数,先靠定位工具找到真凶,再针对性调整,而不是凭感觉乱建索引。