SQL查询性能下降是数据库应用中常见的问题,当业务反馈查询响应变慢时,我们需要通过系统化的方法定位瓶颈,其中慢查询日志和执行计划是最核心的两个排查工具。
一、通过慢查询日志筛选问题SQL
慢查询日志是数据库内置的功能,用于记录执行时间超过指定阈值的SQL语句,我们首先可以通过它找到需要优化的目标查询。
1. 开启慢查询日志
以MySQL为例,我们可以通过以下命令开启慢查询日志,并设置慢查询阈值:
-- 开启慢查询日志 SET GLOBAL slow_query_log = 'ON'; -- 设置慢查询阈值,单位秒,这里设置为1秒,执行超过1秒的查询会被记录 SET GLOBAL long_query_time = 1; -- 设置慢查询日志存储路径 SET GLOBAL slow_query_log_file = '/var/lib/mysql/slow.log';
2. 分析慢查询日志内容
慢查询日志会记录每条慢SQL的执行时间、锁等待时间、返回行数等信息,我们可以通过mysqldumpslow工具快速分析日志:
-- 查看执行时间最长的10条慢SQL mysqldumpslow -s t -t 10 /var/lib/mysql/slow.log
日志中常见的关键信息包括:
- Query_time:SQL总执行时间,数值越大性能问题越严重
- Lock_time:锁等待时间,如果这个值过高可能是锁竞争问题
- Rows_sent:返回给客户端的行数,如果远大于实际需要的数据量可能存在查询冗余
- Rows_examined:数据库扫描的行数,这个值过高通常说明没有使用合适的索引
二、通过执行计划分析查询执行逻辑
找到慢SQL之后,我们需要通过执行计划查看数据库执行这条查询的具体路径,定位性能问题的根源。
1. 获取执行计划
在SQL语句前加上EXPLAIN关键字就可以获取该查询的执行计划,以MySQL为例:
-- 假设我们有一条慢查询SQL EXPLAIN SELECT u.name, o.order_id FROM user u JOIN order o ON u.id = o.user_id WHERE u.age > 18 AND o.status = 1;
2. 执行计划核心字段解读
执行计划返回的结果包含多个字段,我们需要重点关注以下几个:
| 字段名 | 含义 | 性能参考 |
|---|---|---|
| type | 表的访问方式 | 性能从好到坏:system > const > eq_ref > ref > range > index > ALL,出现ALL说明全表扫描,需要优化 |
| key | 实际使用的索引 | 如果为NULL说明没有使用索引,需要检查是否有合适索引 |
| rows | 预估扫描的行数 | 数值越小越好,过大说明索引选择不合理或者没有索引 |
| Extra | 额外执行信息 | 出现Using filesort、Using temporary说明需要额外排序或临时表,性能较差 |
三、常见性能瓶颈与优化方向
结合慢查询日志和执行计划的分析结果,常见的性能瓶颈和优化方向如下:
- 如果执行计划中
type为ALL,key为NULL,说明没有使用索引,需要给查询条件的字段添加合适索引 - 如果
rows扫描行数远大于返回行数,可能是索引区分度不够,需要选择区分度更高的字段建索引 - 如果
Extra出现Using filesort,说明查询的排序没有使用索引,需要给排序字段添加索引 - 如果慢查询日志中
Rows_examined远大于Rows_sent,说明查询返回了多余的数据,可以优化查询条件,只查询需要的字段 - 如果是多表关联查询慢,检查关联字段是否有索引,调整表的关联顺序,小表驱动大表
四、优化验证
完成优化之后,我们可以再次执行EXPLAIN查看执行计划的变化,同时可以在测试环境执行原SQL和优化后的SQL,对比执行时间,确认优化效果:
-- 优化前执行,记录执行时间 SELECT u.name, o.order_id FROM user u JOIN order o ON u.id = o.user_id WHERE u.age > 18 AND o.status = 1; -- 添加索引后执行,对比执行时间 -- 给user表的age字段添加索引 CREATE INDEX idx_user_age ON user(age); -- 给order表的user_id和status字段添加联合索引 CREATE INDEX idx_order_user_status ON order(user_id, status); -- 再次执行查询 SELECT u.name, o.order_id FROM user u JOIN order o ON u.id = o.user_id WHERE u.age > 18 AND o.status = 1;
通过慢查询日志和执行计划结合分析,我们可以快速定位SQL查询的性能瓶颈,针对性优化之后就能有效提升查询效率,保障业务的稳定运行。