当前位置: 代码网 > it编程>数据库>Mysql > MySQL性能优化之慢查询优化实战指南

MySQL性能优化之慢查询优化实战指南

2025年07月07日 Mysql 我要评论
1. 业务场景描述在某电商平台,对商品订单数据进行统计分析时,后台报表接口响应时间经常超过5秒,严重影响业务体验。进一步定位发现,涉及千万级别的order和order_item表,多表join和聚合查

1. 业务场景描述

在某电商平台,对商品订单数据进行统计分析时,后台报表接口响应时间经常超过5秒,严重影响业务体验。进一步定位发现,涉及千万级别的orderorder_item表,多表join和聚合查询导致mysql查询性能瓶颈。为了保证统计接口的实时性与可用性,需要对慢查询进行系统优化。

关键痛点:

  • 表数据量大(订单表超过2000万行)
  • 多表关联和复杂聚合(sum、group by)
  • 高并发读请求影响主库负载

2. 技术选型过程

为了解决上述问题,我们评估了以下几种方案:

方案a:在主库打开慢查询日志+使用explain手动优化

方案b:使用mysql proxy/中间件做sql路由及分片

方案c:引入elasticsearch做离线统计

方案d(最终选型):主库+备库读写分离 + 组合索引优化 + sql重写 + 分区分表方案

选型理由:

  • a方案可快速定位并优化单条sql,但无法构建整体可扩展体系
  • b方案需要中间件改造成本高,团队不具备足够维护经验
  • c方案脱离mysql生态,数据同步延迟高,无法满足实时性
  • d方案在现有架构上扩展成本较低,可渐进式上线,兼顾实时性与可维护性

3. 实现方案详解

3.1 开启慢查询日志与收集数据

my.cnf中开启慢查询日志,并设置合理阈值(例如2秒):

[mysqld]
slow_query_log = on
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
log_queries_not_using_indexes = on

重启后,让mysql开始记录慢查询。

3.2 使用pt-query-digest分析日志

借助percona toolkit:

pt-query-digest /var/log/mysql/slow.log > slow_report.txt

报告中会列出最耗时、最频繁的sql以及全表扫描等信息。

3.3 explain分析瓶颈sql

以典型慢查询为例:

select oi.product_id, sum(oi.quantity) as total_sold
from order_item oi
join `order` o on oi.order_id = o.id
where o.status = 'completed'
  and o.created_at between '2023-01-01' and '2023-06-30'
group by oi.product_id;

执行explain

+----+-------------+-------+------------+------+---------------+------+---------+----------------------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref                  | rows  | filtered | extra       |
+----+-------------+-------+------------+------+---------------+------+---------+----------------------+-------+----------+-------------+
|  1 | simple      | o     | null       | all  | idx_status     | null | null    | null                 |2000000| 10.00    | using where |
|  1 | simple      | oi    | null       | ref  | idx_order_id   | idx_order_id | 4 | test.o.id | 500000| 100.00   | using index |
+----+-------------+-------+------------+------+---------------+------+---------+----------------------+-------+----------+-------------+

可以看到订单表o全表扫描,需要优化索引。

3.4 添加组合索引

针对order(status, created_at)添加组合索引:

alter table `order`
  add index idx_status_created_at (status, created_at);

再次执行explain

| type: range, key: idx_status_created_at, rows: 50000, extra: using where; using index

大幅减少扫描行数。

3.5 sql重写与分区

分区表:

alter table `order`
partition by range ( year(created_at) ) (
  partition p2021 values less than (2022),
  partition p2022 values less than (2023),
  partition pmax values less than maxvalue
);

重写sql使分区裁剪生效:

... where created_at >= '2023-01-01' and created_at < '2023-07-01' ...

保证时间范围在单个或少数分区。

3.6 读写分离

使用mysql proxy或中间件(如atlas、mycat)将读请求路由到从库,减轻主库压力。

js配置示例(sequelize+xorm):

const sequelize = new sequelize('db', 'user', 'pass', {
  dialect: 'mysql',
  replication: {
    read: [{ host: 'slave1', username: 'user', password: 'pass' }],
    write: { host: 'master', username: 'user', password: 'pass' }
  }
});

4. 踩过的坑与解决方案

坑1:索引列顺序错误导致无效索引。

解决:严格按照wheregroup by字段顺序设计组合索引。

坑2:分区表改造在线迁移复杂。

解决:采用pt-online-schema-change工具在线拆分分区、添加索引。

坑3:读写分离一致性问题。

解决:针对关键业务使用session.pin或读写同连接,确保读到最新数据。

坑4:过度使用in子查询引起临时表。

解决:改写为join或exists,或使用窗口函数(mysql 8.0+)。

5. 总结与最佳实践

  • 常规优化步骤:慢日志→分析报告→explain→补索引→sql重写。
  • 大表建议分区分表,结合分区裁剪减少扫描范围。
  • 生产环境上线前使用pt-query-digest+explain验证性能。
  • 读写分离及缓存(如redis)配合使用,可进一步提升读性能。
  • 定期回顾慢日志:随着数据增长,不断迭代优化。

通过以上实战方法,可以将统计接口响应时间从5秒优化至500ms以内。在实际项目中,建议结合自身业务特点,灵活运用上述手段,持续监控并优化数据库性能。

到此这篇关于mysql性能优化之慢查询优化实战指南的文章就介绍到这了,更多相关mysql慢查询优化内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com