mysql如何在执行过程中优化SQL性能_mysql优化策略总结

来源:这里教程网 时间:2026-02-28 20:51:58 作者:

为什么
EXPLAIN
看不出全表扫描但实际很慢?

因为

EXPLAIN
只展示预估执行计划,不反映真实数据分布、锁等待、磁盘 I/O 延迟或临时表溢出。比如
WHERE
条件命中索引,但返回 50 万行结果集,MySQL 仍可能因排序/分组被迫创建内部临时表并写入磁盘。

务必配合
SHOW PROFILE FOR QUERY N
查看各阶段耗时(尤其是
Copying to tmp table
Sorting result
SELECT ... INTO OUTFILE
或流式读取应用层分页,避免一次性拉取超大结果集
检查
tmp_table_size
max_heap_table_size
是否过小,导致内存临时表退化为磁盘临时表

ORDER BY
+
LIMIT
为何有时不走索引?

ORDER BY
字段和
WHERE
条件字段不在同一复合索引中,或索引顺序不匹配排序方向(如索引是
(a, b)
,而查询写
ORDER BY b DESC
),MySQL 可能放弃索引排序,改用文件排序(
Using filesort
)。

优先建立覆盖排序需求的复合索引,例如
WHERE status=1 ORDER BY created_at DESC
→ 建索引
(status, created_at)
避免在
ORDER BY
中使用函数或表达式,如
ORDER BY DATE(created_at)
会失效
LIMIT
很小(如
LIMIT 10
)但偏移量极大(如
OFFSET 100000
)时,即使走索引也要跳过前 10 万行 —— 改用游标分页(
WHERE id > last_seen_id ORDER BY id LIMIT 10

哪些
JOIN
写法会让优化器“放弃治疗”?

MySQL 优化器对多表关联的代价估算较保守,遇到子查询、

OR
条件、函数条件或非等值连接时,常误判驱动表顺序,甚至退化为嵌套循环暴力匹配。

IN (SELECT ...)
改成
JOIN
EXISTS
NOT IN
必须警惕 NULL 导致逻辑错误,优先用
NOT EXISTS
避免
ON a.x = b.y + 1
这类表达式条件,它无法利用
b.y
上的索引
显式用
STRAIGHT_JOIN
强制连接顺序(仅当确认优化器选错且已验证效果)
大表
JOIN
小表时,确保小表有高效过滤条件,并在小表上建好关联字段索引

线上慢查询突然变快,是不是优化成功了?

未必。可能是缓存生效(Query Cache 已废弃,但 InnoDB Buffer Pool 缓存了热点页)、统计信息未更新导致优化器选了更“侥幸”的路径,或并发压力暂时下降。这类“伪优化”会在流量高峰或数据量增长后重现。

执行
ANALYZE TABLE
更新统计信息,再看
EXPLAIN
是否稳定
SELECT SLEEP(1)
模拟低并发,对比高并发下
SHOW PROCESSLIST
中的
State
(如频繁出现
Waiting for table metadata lock
要查长事务)
开启慢查询日志并设置
long_query_time = 0
抽样捕获所有查询,结合
pt-query-digest
分析分布规律

真正可靠的优化,是让最差情况下的 P99 响应时间也落在预期范围内,而不是依赖缓存或运气。索引设计、数据类型精简、避免隐式转换,这些底层约束比任何 SQL 技巧都重要。

相关推荐