MySQL慢查询日志分析:定位索引问题

慢查询日志是定位索引问题的利器。本文从开启日志、分析日志到验证索引,给出完整路径。

MySQL慢查询日志分析:定位索引问题
封面图:ZuCDN · ZuCDN 原创

当数据库响应变慢,MySQL慢查询日志是定位索引问题的第一手证据。它记录了执行时间超过阈值的SQL,通过分析这些语句,可以快速锁定哪些查询缺少索引或索引使用不当。本文将给出从开启日志到验证索引的完整判断路径,并指出常见误区。

开启慢查询日志:先确认记录了什么

慢查询日志默认关闭,需要手动开启。在MySQL配置文件中设置:

slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = 1

long_query_time 定义了“慢”的阈值,单位为秒,建议从1秒开始;log_queries_not_using_indexes 会额外记录所有未使用索引的查询,即使它们执行很快,这对发现潜在索引问题很有帮助。注意,修改配置后需重启MySQL或动态设置全局变量。

分析慢日志:找出候选查询

日志中每条记录包含查询时间、锁等待时间、返回行数、扫描行数以及SQL文本。重点关注扫描行数远大于返回行数的查询,这往往意味着索引缺失或选择性差。例如:

# Query_time: 2.5  Lock_time: 0.0  Rows_sent: 10  Rows_examined: 100000
SELECT * FROM orders WHERE customer_id = 123;

扫描10万行仅返回10行,明显缺少customer_id索引。此时可以结合EXPLAIN验证执行计划。

用EXPLAIN验证索引使用

对候选SQL执行EXPLAIN,观察type列:ALL表示全表扫描,refrange表示使用了索引。若key列为NULL,则未使用索引。例如:

EXPLAIN SELECT * FROM orders WHERE customer_id = 123;

type=ALL,则确认缺少索引。创建索引后再验证:

CREATE INDEX idx_customer_id ON orders(customer_id);
EXPLAIN SELECT * FROM orders WHERE customer_id = 123;

此时type应变为ref,扫描行数大幅减少。

常见误区与失败条件

误区一:只关注慢日志中的SQL。 慢日志只记录超过阈值的查询,但未使用索引的快速查询可能被log_queries_not_using_indexes捕获,否则会被忽略。建议同时开启该选项。

误区二:索引越多越好。 索引会降低写入性能并占用存储空间,应只为高频查询创建必要的索引。在添加索引前,确认查询频率和性能影响。

误区三:忽略复合索引顺序。 复合索引遵循最左前缀原则,若查询条件不包含最左列,索引可能失效。例如INDEX(a,b),查询WHERE b=1不会使用该索引。

失败条件: 即使创建了索引,如果查询条件中使用了函数或隐式类型转换,索引也可能失效。例如WHERE DATE(create_time) = '2023-01-01',会导致全表扫描。此时应改为范围查询或使用生成列。

日志安全与监控:别忽略基础

慢查询日志本身可能包含敏感数据,如用户ID或订单号,应限制文件权限,避免泄露。参考OWASP日志安全速查表,确保日志不被未授权访问。同时,日志是监控的重要数据源,但传统日志与追踪、指标集成较弱,可考虑使用OpenTelemetry等标准来统一采集和分析,提升可观测性。

优化验证:从日志到性能闭环

添加索引后,应再次运行慢查询日志,确认查询时间下降。如果仍有慢查询,可能需要调整索引设计或重写SQL。常见优化包括:

  • 使用覆盖索引避免回表。
  • LIKE '%keyword%'改为全文索引。
  • 拆分大查询为多个小查询。

注意,优化是持续过程,应定期分析慢日志,结合业务变化调整索引。

参考资料

延伸阅读