慢查询优化的第一步是找到慢SQL
MySQL性能问题的绝大多数来自慢查询。优化流程固定:开启慢查询日志、定位慢SQL、用EXPLAIN分析执行计划、针对性加索引或改写SQL、验证效果。跳过定位直接加索引,常见的结果是索引没被使用,问题依旧。先把慢查询日志打开,这是排查的起点。
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
线上建议用pt-query-digest分析慢日志,按总耗时、平均耗时、出现频率排序,优先处理累计影响最大的SQL,而不是单次最慢的。
用EXPLAIN解读执行计划
拿到慢SQL后执行EXPLAIN,重点看type、key、rows三列。type反映访问类型:const、eq_ref、ref是高效命中,range次之,ALL代表全表扫描,是需要消除的。key显示实际使用的索引,为NULL说明没有可用索引。rows是预估扫描行数,行数大而实际返回少,多半是索引选择不当。
EXPLAIN SELECT id, order_no, amount
FROM orders
WHERE user_id = 1001
AND status = 1
ORDER BY create_time DESC;
type=ALL时,需要评估是否新建联合索引。联合索引列顺序遵循最左前缀原则,区分度高的列放前面。
索引设计:联合索引与最左前缀
多条件查询建议建联合索引。以上面的查询为例:
ALTER TABLE orders ADD INDEX idx_user_status_time (user_id, status, create_time);
索引建立后,user_id、user_id+status、user_id+status+create_time三组查询都能命中。联合索引的列顺序按查询条件和区分度权衡:等值条件的列放前面,范围条件(>、<、BETWEEN)放后面,因为范围列之后的列无法使用索引。
避免冗余索引。已有(user_id, status)联合索引时,单列user_id索引是冗余的,占用写入开销且拖慢更新。
常见慢查询的改写方式
几条高频优化套路:
- 避免对索引列做函数运算:WHERE DATE(create_time)=’2026-09-01′ 无法用索引,改成 create_time >= ‘2026-09-01 00:00:00’ AND create_time < ‘2026-09-02’。
- 避免前置通配符:LIKE ‘%keyword%’ 无法走索引,业务允许时改用全文索引或es。
- 分页深翻页用延迟关联:先取主键再回表,而不是直接LIMIT 100000, 20。
-- 深翻页优化示例
SELECT * FROM orders
WHERE id > (SELECT id FROM orders WHERE status = 1 ORDER BY id LIMIT 100000, 1)
ORDER BY id
LIMIT 20;
索引优化后的验证与回退
加索引后重新EXPLAIN确认type提升、rows下降,再用相同数据量压测对比耗时。同时监控加索引后的写性能变化:写多读少的表,索引数量要克制。上线一周内保留旧执行计划对比数据,确认收益后再清理长期未使用的冗余索引。索引优化是持续过程,数据量增长、查询模式变化后,旧索引可能失效,定期重跑慢日志分析才能保持状态。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/mysql-man-cha-xun-you-hua-shi-zhan-cong-zhi-xing-ji-hua-fen/