当数据库响应变慢,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表示全表扫描,ref或range表示使用了索引。若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%'改为全文索引。 - 拆分大查询为多个小查询。
注意,优化是持续过程,应定期分析慢日志,结合业务变化调整索引。
参考资料
延伸阅读
