MySQL 查询太慢怎么优化?

SQL 查询执行很慢,页面响应时间长,需要定位和优化慢查询

解决方案

用 EXPLAIN 分析执行计划 推荐

-- 1. 在慢查询前加 EXPLAIN
EXPLAIN SELECT o.order_no, u.username, o.total_amount
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.status = 1 AND o.created_at > '2026-05-01'
ORDER BY o.created_at DESC
LIMIT 20;

-- 2. 关注这些指标:
-- type: ALL(全表扫描,最差) → index → range → ref → const(最好)
-- key: NULL 表示没用到索引
-- rows: 扫描行数,越少越好
-- Extra: Using filesort / Using temporary 需要优化

-- 3. 根据分析结果添加索引
CREATE INDEX idx_status_created ON orders(status, created_at);

EXPLAIN 是 MySQL 查询优化的第一步,能看到查询是否使用了索引、扫描了多少行、是否有排序等。根据分析结果针对性地添加索引或改写 SQL。

适用场景:任何查询变慢时的第一步诊断

优化索引设计 推荐

-- 常见索引优化策略:

-- 1. 为 WHERE 条件创建复合索引(遵循最左前缀)
CREATE INDEX idx_user_status_time ON orders(user_id, status, created_at);

-- 2. 覆盖索引(避免回表)
CREATE INDEX idx_cover ON orders(user_id, status, created_at, total_amount);
-- 查询只需要索引中的列时,不需要回表查数据

-- 3. 避免索引失效的写法
-- 错误:WHERE YEAR(created_at) = 2026  (函数导致索引失效)
-- 正确:WHERE created_at >= '2026-01-01' AND created_at < '2027-01-01'

-- 错误:WHERE phone LIKE '%1234'  (左模糊导致索引失效)
-- 正确:WHERE phone LIKE '138%'  (右模糊可以用索引)

-- 错误:WHERE status != 1  (不等于可能不走索引)
-- 正确:WHERE status IN (0, 2, 3)  (用 IN 代替)

索引是查询优化最有效的手段。复合索引要把区分度高的列放前面,同时注意避免让索引失效的 SQL 写法。

适用场景:EXPLAIN 显示 type=ALL 或 key=NULL 时

优化 SQL 写法

-- 1. 避免 SELECT *
-- 差:SELECT * FROM orders WHERE user_id = 1001;
-- 好:SELECT order_no, total_amount, status FROM orders WHERE user_id = 1001;

-- 2. 深分页优化
-- 差:SELECT * FROM orders ORDER BY id LIMIT 100000, 20;  (扫描 10 万行)
-- 好:SELECT * FROM orders WHERE id > 100000 ORDER BY id LIMIT 20;  (游标分页)

-- 3. 避免子查询,改用 JOIN
-- 差:SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE status = 1);
-- 好:SELECT DISTINCT u.* FROM users u JOIN orders o ON u.id = o.user_id WHERE o.status = 1;

-- 4. 批量操作代替循环
-- 差:逐条 INSERT
-- 好:INSERT INTO t VALUES (...), (...), (...);  (批量插入)

SQL 写法直接影响执行效率。避免 SELECT *、优化深分页、用 JOIN 代替子查询都是常见的优化手段。

适用场景:索引已经合理但查询仍然慢时

开启慢查询日志持续监控

-- 开启慢查询日志
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;  -- 超过 1 秒记录
SET GLOBAL log_queries_not_using_indexes = ON;

-- 查看慢查询日志文件位置
SHOW VARIABLES LIKE 'slow_query_log_file';

-- 用 mysqldumpslow 分析 Top 10 慢查询
-- mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

-- 或用 pt-query-digest 更详细的分析
-- pt-query-digest /var/log/mysql/slow.log > report.txt

慢查询日志能持续记录执行时间超过阈值的 SQL,配合分析工具找出最需要优化的查询。

适用场景:需要系统性地发现和优化慢查询

注意事项

添加索引会降低写入性能,不要盲目加索引
生产环境修改索引用 pt-online-schema-change 避免锁表
优化前先用 EXPLAIN 确认问题,不要凭感觉优化

相关命令