MySQL查询优化实战:慢查询定位与执行计划深度解读

MySQL慢查询的定位方法

MySQL性能调优的第一步是找到真正需要优化的查询。数据库运维中,慢查询日志是最基础也最有效的定位手段。开启慢查询日志后,MySQL会将执行时间超过long_query_time的SQL语句记录到日志文件中,这是后续所有优化工作的起点。

“`sql
— 查看慢查询日志状态
SHOW VARIABLES LIKE ‘slow_query_log%’;
SHOW VARIABLES LIKE ‘long_query_time’;

— 开启慢查询日志并设置阈值
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1; — 超过1秒记录
SET GLOBAL log_queries_not_using_indexes = ON; — 记录未使用索引的查询

— 使用mysqldumpslow分析慢查询日志
— mysqldumpslow -s t -t 10 /var/lib/mysql/slow.log
“`

mysqldumpslow按总耗时排序输出Top N慢查询,-s t表示按查询时间排序,-t 10表示取前10条。生产环境建议将long_query_time设置为0.5秒甚至0.1秒,捕获更多潜在问题查询。

EXPLAIN执行计划深度解读

拿到慢查询SQL后,使用EXPLAIN分析其执行计划是优化的核心步骤。MySQL 8.0的EXPLAIN输出包含12个字段,关键字段解读:

type:访问类型,从优到劣依次为system > const > eq_ref > ref > range > index > ALL。ALL表示全表扫描,必须优化。index表示全索引扫描,通常也需要优化。

key:实际使用的索引。如果为NULL,说明没有使用索引。

rows:预估扫描行数。这个值越接近实际返回行数,说明索引过滤效率越高。

Extra:额外信息,重点关注以下值:

– Using index:覆盖索引,不需要回表,理想状态
– Using filesort:额外排序操作,需要优化
– Using temporary:使用临时表,常见于GROUP BY和DISTINCT
– Using where:在存储引擎返回数据后进行过滤,说明索引过滤不够充分

“`sql
— 分析慢查询的执行计划
EXPLAIN FORMAT=JSON
SELECT o.order_id, o.amount, c.name
FROM orders o
JOIN customers c ON o.customer_id = c.id
WHERE o.create_time BETWEEN ‘2026-01-01’ AND ‘2026-07-31’
AND o.status = ‘paid’
ORDER BY o.amount DESC
LIMIT 20;
“`

FORMAT=JSON提供更详细的执行计划信息,包括used_columns、attached_condition等,便于精确判断索引使用情况。

索引优化策略

SQL查询优化的核心是让查询尽可能走覆盖索引,减少回表次数和扫描行数。

复合索引的最左前缀原则:索引(a, b, c)可以用于查询条件a、a,b、a,b,c,但不能用于b,c或c单独查询。复合索引的字段顺序应将等值查询字段放在前面,范围查询字段放在后面。

“`sql
— 为订单查询创建复合索引
CREATE INDEX idx_orders_status_createtime ON orders(status, create_time);

— 覆盖索引避免回表
CREATE INDEX idx_orders_covering ON orders(status, create_time, order_id, amount);

— 查询只需索引中的列,无需回表
SELECT order_id, amount
FROM orders
WHERE status = ‘paid’ AND create_time BETWEEN ‘2026-01-01’ AND ‘2026-07-31’;
“`

避免索引失效的场景:对索引列使用函数、隐式类型转换、LIKE前缀通配符、OR条件中部分字段无索引,都会导致索引失效。分库分表方案中,路由字段的索引设计直接影响跨分片查询的性能。

JOIN查询优化

多表JOIN是慢查询的高发区域。优化原则:驱动表选择数据量小的表,被驱动表关联字段必须有索引,避免JOIN后在大结果集上排序。

“`sql
— 子查询改写为JOIN
— 慢写法
SELECT * FROM orders
WHERE customer_id IN (SELECT id FROM customers WHERE region = ‘east’);

— 优化写法
SELECT o.* FROM orders o
INNER JOIN customers c ON o.customer_id = c.id
WHERE c.region = ‘east’;
“`

MySQL 8.0对子查询的优化有所改善,但在复杂场景下,JOIN仍然比子查询更高效。对于数据量极大的表关联,考虑在应用层分批查询后内存合并,减少数据库层的计算压力。

数据库高可用架构下的查询优化

数据库高可用架构通常采用主从复制+读写分离。查询优化需要考虑主从延迟对业务的影响。写入后立即读取可能读到从库的旧数据,解决方案包括:强制走主库读取、使用semi-sync复制减少延迟、在应用层缓存最近写入的数据。数据备份恢复策略应定期验证可恢复性,避免在故障时发现备份不可用。国产数据库(如OceanBase、TiDB)的查询优化器与MySQL存在差异,迁移时需要重新评估执行计划。SQL查询优化不是孤立的技术工作,需要结合业务场景、数据分布和基础设施架构进行系统性优化。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/mysql-cha-xun-you-hua-shi-zhan-man-cha-xun-ding-wei-yu-zhi/

(0)
小编小编
上一篇 9小时前
下一篇 9小时前

相关推荐