news 2026/4/17 18:33:01

MySQL性能优化:从慢查询到毫秒级响应

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL性能优化:从慢查询到毫秒级响应

前言

去年双十一,我们的数据库成了最大的瓶颈。一个简单的订单查询需要5秒,用户投诉不断。经过系统的优化,我们将查询时间降到了50ms以内。

这篇文章分享我们在MySQL优化过程中的实战经验。


一、问题发现:慢查询日志

首先,我们开启了MySQL的慢查询日志:

sql

-- 开启慢查询日志 SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1; -- 记录超过1秒的查询 SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';

分析日志后,发现最慢的查询:

sql

SELECT * FROM orders WHERE user_id = 12345 AND status = 'pending' AND created_at > '2024-01-01'; -- 执行时间:5.2秒 -- 扫描行数:2,000,000行


二、优化策略一:添加索引

2.1 问题分析

使用EXPLAIN查看执行计划:

sql

EXPLAIN SELECT * FROM orders WHERE user_id = 12345 AND status = 'pending' AND created_at > '2024-01-01';

结果:

+----+-------------+--------+------+---------------+------+---------+------+---------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+------+---------------+------+---------+------+---------+-------------+ | 1 | SIMPLE | orders | ALL | NULL | NULL | NULL | NULL | 2000000 | Using where | +----+-------------+--------+------+---------------+------+---------+------+---------+-------------+

问题type=ALL表示全表扫描,没有使用索引。

2.2 创建复合索引

sql

Copy code

-- 创建复合索引 CREATE INDEX idx_user_status_created ON orders(user_id, status, created_at);

再次执行查询:

sql

EXPLAIN SELECT * FROM orders WHERE user_id = 12345 AND status = 'pending' AND created_at > '2024-01-01';

结果:

+----+-------------+--------+-------+-------------------------+-------------------------+---------+------+------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+-------+-------------------------+-------------------------+---------+------+------+-----------------------+ | 1 | SIMPLE | orders | range | idx_user_status_created | idx_user_status_created | 18 | NULL | 150 | Using index condition | +----+-------------+--------+-------+-------------------------+-------------------------+---------+------+------+-----------------------+

结果

  • 扫描行数从200万降到150行
  • 查询时间从5.2秒降到50ms

三、优化策略二:避免SELECT *

3.1 问题

sql

SELECT * FROM orders WHERE user_id = 12345;

这个查询会返回所有字段,包括大字段(如descriptionmetadata),浪费带宽和内存。

3.2 只查询需要的字段

sql

SELECT id, user_id, status, total_amount, created_at FROM orders WHERE user_id = 12345;

结果

  • 数据传输量减少70%
  • 查询时间从50ms降到15ms

四、优化策略三:分页优化

4.1 问题:深度分页

sql

-- 查询第10000页,每页20条 SELECT * FROM orders ORDER BY created_at DESC LIMIT 200000, 20; -- 执行时间:3.5秒

MySQL需要扫描前200020行,然后丢弃前200000行。

4.2 使用游标分页

sql

-- 第一页 SELECT id, user_id, status, created_at FROM orders ORDER BY id DESC LIMIT 20; -- 假设最后一条记录的id是980 -- 第二页 SELECT id, user_id, status, created_at FROM orders WHERE id < 980 ORDER BY id DESC LIMIT 20;

结果

  • 查询时间从3.5秒降到20ms
  • 不受页数影响

五、优化策略四:查询缓存

5.1 应用层缓存

python

import redis import json redis_client = redis.Redis(host='localhost', port=6379, db=0) def get_user_orders(user_id): # 尝试从缓存读取 cache_key = f"user_orders:{user_id}" cached = redis_client.get(cache_key) if cached: return json.loads(cached) # 缓存未命中,查询数据库 query = """ SELECT id, user_id, status, total_amount, created_at FROM orders WHERE user_id = %s ORDER BY created_at DESC LIMIT 20 """ cursor.execute(query, (user_id,)) orders = cursor.fetchall() # 写入缓存,过期时间5分钟 redis_client.setex(cache_key, 300, json.dumps(orders)) return orders

结果

  • 缓存命中率:85%
  • 平均响应时间从15ms降到2ms

六、优化策略五:读写分离

6.1 架构设计

┌─────────────┐ │ 应用服务 │ └──────┬──────┘ │ ┌────────┴────────┐ │ │ 写操作 读操作 │ │ ┌────▼────┐ ┌───▼────┐ │ 主库 │──────▶│ 从库1 │ │ (Master)│ │ (Slave) │ └─────────┘ └────────┘ │ ┌────▼────┐ │ 从库2 │ │ (Slave) │ └─────────┘

6.2 代码实现

python

import pymysql from random import choice # 主库配置 MASTER_CONFIG = { 'host': 'master-db.example.com', 'user': 'root', 'password': 'password', 'database': 'mydb' } # 从库配置 SLAVE_CONFIGS = [ { 'host': 'slave1-db.example.com', 'user': 'root', 'password': 'password', 'database': 'mydb' }, { 'host': 'slave2-db.example.com', 'user': 'root', 'password': 'password', 'database': 'mydb' } ] def get_master_connection(): return pymysql.connect(**MASTER_CONFIG) def get_slave_connection(): # 随机选择一个从库 config = choice(SLAVE_CONFIGS) return pymysql.connect(**config) # 写操作使用主库 def create_order(user_id, amount): conn = get_master_connection() cursor = conn.cursor() cursor.execute( "INSERT INTO orders (user_id, amount) VALUES (%s, %s)", (user_id, amount) ) conn.commit() conn.close() # 读操作使用从库 def get_orders(user_id): conn = get_slave_connection() cursor = conn.cursor() cursor.execute( "SELECT * FROM orders WHERE user_id = %s", (user_id,) ) orders = cursor.fetchall() conn.close() return orders

结果

  • 主库写入压力降低60%
  • 读操作QPS提升3倍

七、优化策略六:分库分表

7.1 问题:单表数据过大

我们的orders表有5000万条记录,即使有索引,查询也很慢。

7.2 按用户ID分表

python

def get_table_name(user_id): # 按用户ID取模,分成16张表 table_index = user_id % 16 return f"orders_{table_index}" def create_order(user_id, amount): table_name = get_table_name(user_id) query = f""" INSERT INTO {table_name} (user_id, amount, created_at) VALUES (%s, %s, NOW()) """ cursor.execute(query, (user_id, amount)) def get_user_orders(user_id): table_name = get_table_name(user_id) query = f""" SELECT * FROM {table_name} WHERE user_id = %s ORDER BY created_at DESC LIMIT 20 """ cursor.execute(query, (user_id,)) return cursor.fetchall()

结果

  • 单表数据量从5000万降到300万
  • 查询时间从200ms降到10ms

八、国际化团队协作

在数据库优化过程中,我们的DBA团队分布在不同国家。为了确保优化方案和技术文档能够被所有团队成员准确理解,我们使用了同言翻译(Transync AI)来翻译数据库优化报告和技术规范,大大提高了跨国团队的协作效率。


九、监控和告警

9.1 慢查询监控

python

import time import logging def query_with_monitor(query, params): start_time = time.time() cursor.execute(query, params) duration = time.time() - start_time # 记录慢查询 if duration > 0.1: # 超过100ms logging.warning(f"慢查询: {query}, 耗时: {duration}s") return cursor.fetchall()

9.2 数据库连接池监控

python

from dbutils.pooled_db import PooledDB import pymysql pool = PooledDB( creator=pymysql, maxconnections=20, mincached=5, maxcached=10, blocking=True, host='localhost', user='root', password='password', database='mydb' ) def get_pool_status(): return { 'total': pool._maxconnections, 'active': pool._connections, 'idle': pool._idle_cache }


十、性能对比

指标优化前优化后提升
平均查询时间5200ms50ms-99%
QPS2005000+2400%
数据库CPU85%25%-71%
慢查询数量5000/天10/天-99.8%
缓存命中率0%85%-

十一、最佳实践总结

  1. 合理使用索引:为高频查询字段创建索引;
  2. **避免SELECT ***:只查询需要的字段;
  3. 优化分页:使用游标分页代替LIMIT深度分页;
  4. 引入缓存:减少数据库访问压力;
  5. 读写分离:分散数据库负载;
  6. 分库分表:降低单表数据量;
  7. 监控告警:及时发现性能问题。

十二、常见陷阱

陷阱1:过度索引

sql

-- ❌ 不好的做法:为每个字段都创建索引 CREATE INDEX idx_user_id ON orders(user_id); CREATE INDEX idx_status ON orders(status); CREATE INDEX idx_created_at ON orders(created_at); CREATE INDEX idx_amount ON orders(amount); -- ✅ 好的做法:创建复合索引 CREATE INDEX idx_user_status_created ON orders(user_id, status, created_at);

陷阱2:索引失效

sql

-- ❌ 使用函数导致索引失效 SELECT * FROM orders WHERE DATE(created_at) = '2024-01-01'; -- ✅ 改写查询条件 SELECT * FROM orders WHERE created_at >= '2024-01-01 00:00:00' AND created_at < '2024-01-02 00:00:00';

陷阱3:N+1查询问题

python

# ❌ N+1查询问题 orders = Order.query.filter_by(user_id=123).all() for order in orders: user = User.query.get(order.user_id) # 每次都查询数据库 print(user.name) # ✅ 使用JOIN一次性查询 orders = db.session.query(Order, User)\ .join(User, Order.user_id == User.id)\ .filter(Order.user_id == 123)\ .all()


十三、工具推荐

  • MySQL Workbench:可视化数据库管理
  • Percona Toolkit:MySQL性能分析工具集
  • pt-query-digest:慢查询日志分析
  • Prometheus + Grafana:数据库监控
  • Adminer:轻量级数据库管理工具

十四、结语

数据库优化是一个持续的过程,需要根据业务场景不断调整。没有银弹,只有适合自己业务的方案。

希望这篇文章能帮助你解决数据库性能问题。如果你有其他优化经验,欢迎在评论区分享!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 7:04:00

音频质量检测进入AI时代,Dify 1.7.0如何重新定义行业标准?

第一章&#xff1a;音频质量检测进入AI时代传统音频质量检测依赖人工听测与基于信号的客观指标&#xff08;如信噪比、总谐波失真&#xff09;&#xff0c;不仅效率低下&#xff0c;且难以捕捉人耳感知层面的细微差异。随着深度学习技术的发展&#xff0c;AI正逐步接管这一任务…

作者头像 李华
网站建设 2026/4/18 5:37:46

8 个继续教育论文工具,AI 降重查重率优化推荐

8 个继续教育论文工具&#xff0c;AI 降重查重率优化推荐 论文写作的困境&#xff1a;时间与质量的双重挑战 对于继续教育领域的学生来说&#xff0c;撰写毕业论文是一项既重要又充满挑战的任务。它不仅是对学习成果的总结&#xff0c;更是对未来职业发展的重要铺垫。然而&am…

作者头像 李华
网站建设 2026/4/18 11:18:32

9 个专科生任务书写作工具,AI 格式优化推荐

9 个专科生任务书写作工具&#xff0c;AI 格式优化推荐 论文写作的“战场”&#xff0c;你真的准备好了吗&#xff1f; 对于专科生来说&#xff0c;写任务书、文献综述、论文降重这些环节&#xff0c;就像是在一场没有硝烟的战斗中不断挣扎。时间总是不够用&#xff0c;任务却一…

作者头像 李华
网站建设 2026/4/18 6:49:08

9 个专科生论文降重工具,AI 写作推荐与查重优化

9 个专科生论文降重工具&#xff0c;AI 写作推荐与查重优化 论文写作的困境&#xff1a;时间、重复率与反复修改的重担 对于大多数专科生来说&#xff0c;毕业论文不仅是学术生涯中的一次重要挑战&#xff0c;更是对综合能力的一次全面检验。然而&#xff0c;在实际操作过程中&…

作者头像 李华
网站建设 2026/4/17 15:17:29

污染物来源分析不再难:基于R语言的PM2.5溯源实战案例解析

第一章&#xff1a;环境监测中PM2.5溯源的技术挑战在现代城市化进程中&#xff0c;PM2.5污染已成为影响公共健康和生态环境的重要因素。准确识别其来源是制定有效治理策略的前提&#xff0c;然而PM2.5的溯源过程面临多重技术挑战。复杂的大气混合效应 PM2.5颗粒物来源于多种渠道…

作者头像 李华
网站建设 2026/4/18 10:50:25

3年踩坑总结:Dify中Agent工具版本演进的最佳实践路径

第一章&#xff1a;Agent 工具的 Dify 版本管理在构建基于 Agent 的智能应用时&#xff0c;Dify 提供了一套完整的版本控制系统&#xff0c;帮助开发者高效管理 Agent 工具的迭代过程。通过版本管理&#xff0c;团队可以在不中断服务的前提下进行功能更新、回滚错误变更&#x…

作者头像 李华