1. MySQL慢查询日志:数据库性能优化的第一道防线
当线上数据库出现性能瓶颈时,慢查询日志就像数据库系统的"黑匣子",记录了所有执行时间超过阈值的SQL语句。我管理过多个千万级数据量的MySQL实例,发现80%的性能问题都能通过分析慢查询日志定位到根源。
开启慢查询日志只需在my.cnf配置文件中添加几行参数:
ini复制slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 1 # 超过1秒的查询会被记录
log_queries_not_using_indexes = 1 # 记录未使用索引的查询
注意:生产环境建议先将long_query_time设为2-3秒,待收集足够样本后再逐步调低阈值,避免日志文件暴涨影响磁盘IO。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 慢查询日志分析实战:从海量日志中提取黄金信息
2.1 使用mysqldumpslow工具快速定位问题SQL
MySQL自带的mysqldumpslow工具能对慢查询日志进行初步归类分析。以下是我最常用的几种分析模式:
bash复制# 按平均执行时间排序
mysqldumpslow -s at /var/log/mysql/mysql-slow.log
# 按出现次数排序
mysqldumpslow -s c /var/log/mysql/mysql-slow.log
# 分析特定类型的查询
mysqldumpslow -g "SELECT" /var/log/mysql/mysql-slow.log
2.2 使用pt-query-digest进行专业级分析
Percona Toolkit中的pt-query-digest提供了更强大的分析能力。安装后运行:
bash复制pt-query-digest /var/log/mysql/mysql-slow.log > slow_report.txt
生成的报告会包含:
- 执行时间最长的TOP SQL
- 锁等待时间最长的查询
- 执行频率最高的慢查询
- 每种SQL的响应时间分布直方图
3. EXPLAIN深度解析:看懂MySQL执行计划
3.1 执行计划关键字段解读
拿到慢查询SQL后,EXPLAIN命令是我们的核心诊断工具。以下是我特别关注的几个字段:
sql复制EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 'paid';
| 字段 | 理想值 | 问题值 | 含义 |
|---|---|---|---|
| type | const, ref, range | ALL | 扫描类型,ALL表示全表扫描 |
| key | 索引名 | NULL | 实际使用的索引 |
| rows | 小数值 | 大数值 | 预估扫描行数 |
| Extra | Using index | Using filesort | 额外信息,显示是否使用临时表或文件排序 |
3.2 常见执行计划问题与解决方案
-
全表扫描(type=ALL)
- 现象:没有使用任何索引
- 解决:为WHERE条件字段添加复合索引
-
索引失效
- 现象:key列显示使用了索引但rows值仍然很高
- 检查:索引字段是否参与了计算或函数处理
-
文件排序(Using filesort)
- 现象:ORDER BY没有使用索引排序
- 解决:为排序字段建立索引或调整索引顺序
4. 索引优化实战:从原理到最佳实践
4.1 B+树索引原理与设计原则
MySQL索引采用B+树结构,理解这一点对索引设计至关重要:
- 索引列的选择性越高越好(如手机号比性别更适合建索引)
- 复合索引遵循最左前缀原则
- 索引列尽量不为NULL(NULL值会使索引复杂度增加)
4.2 高频场景索引优化方案
场景1:多条件查询
sql复制SELECT * FROM products
WHERE category = 'electronics'
AND price > 1000
AND stock > 0
优化方案:创建(category, price, stock)的复合索引
场景2:排序+筛选
sql复制SELECT * FROM articles
WHERE user_id = 123
ORDER BY created_at DESC
优化方案:创建(user_id, created_at)的复合索引
场景3:分页查询优化
sql复制SELECT * FROM orders
WHERE user_id = 456
ORDER BY id DESC
LIMIT 10000, 20
优化方案:改为基于游标的分页(记录上一页最后一条记录的ID)
5. 高级优化技巧与避坑指南
5.1 索引合并优化
MySQL 5.7+支持index merge优化,但有时手动合并索引效果更好。例如:
sql复制SELECT * FROM users
WHERE phone = '13800138000' OR email = 'test@example.com'
可以创建(phone, email)的复合索引替代两个单列索引的合并。
5.2 隐式类型转换陷阱
常见于字符串字段与数字比较:
sql复制SELECT * FROM products WHERE sku = 12345 # sku是varchar类型
这会导致索引失效,必须确保类型一致:
sql复制SELECT * FROM products WHERE sku = '12345'
5.3 覆盖索引的妙用
当查询的所有字段都包含在索引中时,MySQL可以直接从索引获取数据而无需回表:
sql复制-- 普通查询
SELECT user_id, username FROM users WHERE phone = '13800138000'
-- 优化方案:创建(phone, user_id, username)的复合索引
6. 性能优化闭环:监控与持续改进
6.1 建立性能基准
优化前后应该记录关键指标:
- QPS(每秒查询数)
- 平均响应时间
- 95分位响应时间
- 错误率
6.2 自动化监控方案
推荐使用Prometheus + Grafana搭建监控系统,主要监控:
- 慢查询数量变化
- 索引使用情况
- 锁等待时间
- 连接数波动
我在实际项目中发现,定期(如每周)分析慢查询日志并优化TOP 10慢查询,能使数据库性能保持最佳状态。记住一个原则:索引不是越多越好,每个额外的索引都会增加写入开销。理想的索引策略是基于实际查询模式持续调整优化的过程。
