数据库性能优化完全指南:从慢查询到高效查询

前言

上周五晚上8点,生产环境数据库突然变慢,订单查询从100ms飙升到5000ms。紧急排查后,我们发现是几条没有索引的查询语句导致的。

这次事件让我深刻认识到数据库优化的重要性。这篇文章总结了我们的优化经验。


一、识别慢查询

1.1 启用慢查询日志

-- MySQL配置 SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1; -- 1秒以上的查询记录 SET GLOBAL log_queries_not_using_indexes = 'ON'; -- 查看慢查询日志 SHOW VARIABLES LIKE 'slow_query%';

1.2 分析慢查询

# 使用pt-query-digest分析慢查询日志 pt-query-digest /var/log/mysql/slow.log > slow_query_report.txt # 查看报告 cat slow_query_report.txt # 输出格式: # Count: 50 time=5.23s Lock=0s Rows_sent=100 Rows_examined=1000000 # SELECT * FROM orders WHERE created_at > ?

1.3 使用EXPLAIN分析查询计划

-- 查看查询执行计划 EXPLAIN SELECT * FROM orders WHERE user_id = 123; -- 输出示例: -- id | select_type | table | type | possible_keys | key | rows | Extra -- 1 | SIMPLE | orders | const | PRIMARY | PRIMARY | 1 | -- 关键字段说明: -- type: ALL(全表扫描)< INDEX < RANGE < REF < EQ_REF < CONST -- rows: 扫描行数,越少越好 -- Extra: Using index(很好)、Using where(需要优化)

二、索引优化

2.1 添加单列索引

-- 现象:查询缓慢 EXPLAIN SELECT * FROM orders WHERE user_id = 123; -- rows: 500000(全表扫描) -- 解决:添加索引 CREATE INDEX idx_user_id ON orders(user_id); -- 验证 EXPLAIN SELECT * FROM orders WHERE user_id = 123; -- rows: 100(扫描行数大幅减少)

2.2 复合索引

-- 查询条件:WHERE user_id = 123 AND status = 'pending' EXPLAIN SELECT * FROM orders WHERE user_id = 123 AND status = 'pending'; -- rows: 50000(仍然扫描很多行) -- 添加复合索引 CREATE INDEX idx_user_status ON orders(user_id, status); -- 验证 EXPLAIN SELECT * FROM orders WHERE user_id = 123 AND status = 'pending'; -- rows: 10(显著改善)

2.3 覆盖索引

-- 查询只需要三列,不需要回表 EXPLAIN SELECT user_id, status, created_at FROM orders WHERE user_id = 123; -- Extra: Using where; Using index(已使用覆盖索引) -- 创建覆盖索引 CREATE INDEX idx_user_cover ON orders(user_id, status, created_at); -- 现在查询完全走索引,无需回表

2.4 索引最佳实践

-- ❌ 错误:在WHERE中使用函数 SELECT * FROM orders WHERE YEAR(created_at) = 2024; -- 无法使用索引 -- ✅ 正确:用范围查询 SELECT * FROM orders WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01'; -- 可以使用索引 -- ❌ 错误:索引列参与计算 SELECT * FROM orders WHERE amount * 2 > 1000; -- ✅ 正确:常数参与计算 SELECT * FROM orders WHERE amount > 500; -- ❌ 错误:使用LIKE '%keyword%' SELECT * FROM users WHERE name LIKE '%张%'; -- ✅ 正确:使用LIKE 'keyword%' SELECT * FROM users WHERE name LIKE '张%';

三、查询优化

3.1 避免SELECT *

-- ❌ 差:返回所有列 SELECT * FROM orders; -- 返回30列,网络传输大 -- ✅ 好:只返回需要的列 SELECT order_id, user_id, total_amount FROM orders;

3.2 JOIN优化

-- ❌ 低效:多次JOIN SELECT * FROM orders o JOIN users u ON o.user_id = u.user_id JOIN products p ON o.product_id = p.product_id JOIN categories c ON p.category_id = c.category_id WHERE o.created_at > '2024-01-01'; -- 扫描4个表,可能百万级行数 -- ✅ 优化:缩小数据集再JOIN SELECT o.*, u.name FROM ( SELECT order_id, user_id FROM orders WHERE created_at > '2024-01-01' LIMIT 1000 ) o JOIN users u ON o.user_id = u.user_id;

3.3 子查询优化

-- ❌ 低效:相关子查询 SELECT * FROM orders o WHERE user_id IN ( SELECT user_id FROM users WHERE vip = 1 ); -- 对每一行orders都执行一次子查询 -- ✅ 优化:用JOIN替换 SELECT o.* FROM orders o INNER JOIN users u ON o.user_id = u.user_id WHERE u.vip = 1;

3.4 聚合查询优化

-- ❌ 低效:GROUP BY后过滤 SELECT user_id, COUNT(*) as order_count FROM orders GROUP BY user_id HAVING order_count > 10; -- ✅ 优化:先过滤后聚合 SELECT user_id, COUNT(*) as order_count FROM orders WHERE created_at > DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY user_id HAVING COUNT(*) > 10; ``*

四、分页查询优化

4.1 常见的分页问题

-- ❌ 低效:深分页 SELECT * FROM orders ORDER BY created_at DESC LIMIT 999990, 10; -- 需要扫描1000000行 -- ✅ 优化1:使用覆盖索引 + 回表 SELECT * FROM orders WHERE order_id > ( SELECT order_id FROM orders ORDER BY created_at DESC LIMIT 999990, 1 ) ORDER BY created_at DESC LIMIT 10; -- ✅ 优化2:使用ID偏移(最推荐) SELECT * FROM orders WHERE order_id > 999990 ORDER BY order_id DESC LIMIT 10;

4.2 游标分页

# Python实现游标分页 def fetch_orders(cursor=None, limit=10): if cursor is None: query = "SELECT * FROM orders ORDER BY order_id DESC LIMIT ?" params = [limit + 1] else: query = "SELECT * FROM orders WHERE order_id < ? ORDER BY order_id DESC LIMIT ?" params = [cursor, limit + 1] results = db.execute(query, params).fetchall() has_more = len(results) > limit orders = results[:limit] next_cursor = orders[-1]['order_id'] if orders else None return { 'orders': orders, 'has_more': has_more, 'next_cursor': next_cursor }

五、缓存策略

5.1 查询缓存

import redis import json from datetime import timedelta redis_client = redis.Redis(host='localhost', port=6379, db=0) def get_user_orders(user_id, cache_ttl=3600): cache_key = f"user_orders:{user_id}" # 先查缓存 cached = redis_client.get(cache_key) if cached: return json.loads(cached) # 缓存未命中,查询数据库 orders = db.query( "SELECT * FROM orders WHERE user_id = ? ORDER BY created_at DESC LIMIT 100", [user_id] ) # 写入缓存 redis_client.setex( cache_key, cache_ttl, json.dumps(orders) ) return orders ``*

5.2 缓存失效策略

# 写入新订单时,清理相关缓存 def create_order(user_id, order_data): order = db.insert('orders', order_data) # 清理用户订单缓存 redis_client.delete(f"user_orders:{user_id}") # 清理统计缓存 redis_client.delete(f"user_stats:{user_id}") return order

六、分表分库

6.1 水平分表

# 按user_id取模分表 def get_order_table(user_id): table_index = user_id % 10 return f"orders_{table_index}" def insert_order(user_id, order_data): table = get_order_table(user_id) db.insert(table, order_data) def query_orders(user_id): table = get_order_table(user_id) return db.query(f"SELECT * FROM {table} WHERE user_id = ?", [user_id])

6.2 分表建表脚本

-- 创建10个订单表 CREATE TABLE orders_0 ( order_id BIGINT PRIMARY KEY, user_id BIGINT NOT NULL, total_amount DECIMAL(10, 2), created_at TIMESTAMP, INDEX idx_user_id (user_id) ) ENGINE=InnoDB; -- 重复10次,orders_0 到 orders_9 -- ...

七、批量操作优化

7.1 批量插入

-- ❌ 低效:逐条插入 INSERT INTO products (name, price) VALUES ('产品1', 99.99); INSERT INTO products (name, price) VALUES ('产品2', 199.99); INSERT INTO products (name, price) VALUES ('产品3', 299.99); -- 需要3次网络往返 -- ✅ 优化:批量插入 INSERT INTO products (name, price) VALUES ('产品1', 99.99), ('产品2', 199.99), ('产品3', 299.99); -- 只需1次网络往返

7.2 批量更新

# 批量更新订单状态 def update_orders_status(order_ids, status): # 分批更新,避免锁表太久 batch_size = 1000 for i in range(0, len(order_ids), batch_size): batch = order_ids[i:i + batch_size] placeholders = ','.join('?' * len(batch)) db.execute( f"UPDATE orders SET status = ? WHERE order_id IN ({placeholders})", [status] + batch )

八、锁与事务优化

8.1 避免长事务

# ❌ 差:事务包含太多操作 def process_order(order_id): db.begin_transaction() order = db.query("SELECT * FROM orders WHERE order_id = ?", [order_id]) # 调用外部API(可能很慢) payment_result = call_payment_api(order.total_amount) db.update("orders", {"status": "paid"}, {"order_id": order_id}) db.commit() # ✅ 优化:缩小事务范围 def process_order(order_id): # 外部API调用不在事务内 payment_result = call_payment_api(order.total_amount) # 只有最小的数据库操作在事务内 db.begin_transaction() db.update("orders", {"status": "paid"}, {"order_id": order_id}) db.commit()

8.2 事务隔离级别

-- 查看当前隔离级别 SHOW VARIABLES LIKE 'transaction_isolation'; -- 设置隔离级别 -- READ UNCOMMITTED: 最低,性能最好,数据安全性最差 -- READ COMMITTED: 避免脏读 -- REPEATABLE READ: MySQL默认,避免脏读和不可重复读 -- SERIALIZABLE: 最高,数据安全性最好,性能最差 SET GLOBAL transaction_isolation = 'READ_COMMITTED';

九、监控与告警

9.1 关键指标监控

# 使用Prometheus监控数据库 from prometheus_client import Counter, Histogram, Gauge # 查询计数 query_count = Counter( 'db_queries_total', 'Total database queries', ['query_type'] ) # 查询延迟 query_duration = Histogram( 'db_query_duration_seconds', 'Database query duration', buckets=[0.01, 0.05, 0.1, 0.5, 1.0, 5.0] ) # 连接池使用情况 connection_pool_size = Gauge( 'db_connection_pool_size', 'Database connection pool size' ) # 记录查询时间 import time start = time.time() result = db.query("SELECT * FROM orders WHERE user_id = ?", [123]) duration = time.time() - start query_duration.observe(duration)

9.2 告警规则

# Prometheus告警规则 groups: - name: database rules: # 查询延迟超过1秒 - alert: SlowQuery expr: rate(db_query_duration_seconds_bucket{le="1"}[5m]) > 0.1 for: 5m annotations: summary: "检测到慢查询" # 连接池使用率超过80% - alert: HighConnectionPoolUsage expr: db_connection_pool_size / 10 > 0.8 for: 5m annotations: summary: "数据库连接池使用率过高"

十、全球团队技术分享

我们团队分布在多个时区,定期进行数据库优化的技术分享会议。在英文和中文交替的讨论中,我们使用同言翻译(Transync AI)进行实时同声传译,确保每位工程师都能准确理解复杂的性能优化方案和技术细节,大幅提高了全球团队的协作效率。


十一、性能对比

优化前优化项优化后提升
2000ms添加索引150ms93%
150ms使用缓存10ms93%
深分页1000msID偏移分页50ms95%
全表扫描查询缓存1ms99%

十二、优化检查清单

  • 分析慢查询日志,找出耗时查询
  • 为WHERE条件列添加索引
  • 创建覆盖索引减少回表
  • 避免SELECT *,只查询需要的列
  • 优化JOIN和子查询
  • 实现查询缓存
  • 处理深分页问题
  • 实现批量操作
  • 缩小事务范围
  • 监控关键指标
  • 设置性能告警*

十三、推荐工具

Percona Monitoring and Management (PMM) - 数据库监控 MySQL Workbench - 可视化管理 DBeaver - 数据库工具 Sequel Pro - MySQL客户端

十四、结语

数据库优化是一个持续的过程。不是一次性的事情,而是需要持续监控、分析和改进。

核心思想:找到慢查询 → 分析原因 → 制定方案 → 实施优化 → 验证效果 → 持续监控

希望这篇文章能帮助你的系统跑得更快。欢迎在评论区分享你的优化经验!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1168570.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vscode中只在固定后缀的文件中搜索

我就只想搜.c.h文件1.Ctrlshiftp2.输入setting&#xff0c;选择3.vscode只有排除&#xff0c;没有包含&#xff1b;也就是说只有黑名单&#xff0c;没有白名单&#xff1b;所以把不需要的文件都弄进去&#xff0c;保存一下。{// 排除常见无需搜索的目录"search.exclude&qu…

2026年高端智能客服SCRM哪家靠谱?腾讯企业微信四轮投资服务商微盛·企微管家给出选型建议

2026年&#xff0c;选错SCRM可能让企业陷入数据孤岛与转化困境2026年&#xff0c;客户服务已进入「AI人性化」时代。数据显示&#xff0c;75%的企业因选错SCRM系统&#xff0c;面临数据孤岛、转化低迷等问题——要么系统与企业微信生态不兼容&#xff0c;导致客户信息分散&…

从SolidWorks中导出机器人URDF模型

要把通过SolidWorks创建的机器人模型导出为URDF集成到ROS中&#xff0c;需要通过一个插件实现。 SolidWorks URDF导出插件的基础使用方法参考这篇文章 这里补充一些实用的操作。 通过添加草图实现基准轴和基准坐标系的定位 这需要你对SolidWorks的操作有一定的了解。 有时候…

大语言模型助力高效办公、论文与项目撰写、数据分析、机器学习与深度学习建模

对于机器学习与深度学习建模&#xff0c;ChatGPT与DeepSeek不仅能为科研人员提供基础的建模框架&#xff0c;还能帮助其优化算法参数&#xff0c;甚至根据数据特点自动推荐合适的算法。特别是在深度学习模型的调参过程中&#xff0c;ChatGPT可以通过与科研人员的互动&#xff0…

人工智能应用-机器视觉:AI 美颜 07.妆容迁移

研究者将这一思想应用于美颜场景&#xff1a;先把一张人脸照片分解成“内容因子”和“风格因子”&#xff0c;其中内容因子代表是谁的脸&#xff08;身份特征&#xff09;&#xff0c;风格因子则代表脸部的美丑胖瘦、是否带妆、表情等。如果分解足够准确&#xff0c;就可以把漂…

课程论文还在熬夜赶稿?虎贲等考 AI:一键解锁 “高分学术捷径”

学期末的课程论文&#xff0c;堪称大学生的 “期末魔咒”。选题跑偏、文献难寻、数据图表不会做、查重超标反复改…… 这些难题让无数同学陷入 “熬夜赶稿 - 导师打回 - 重新熬夜” 的死循环。 难道课程论文只能靠 “凑字数、堆文献” 应付交差&#xff1f;答案当然是不&#…

立体仓库堆垛机远程监控运维管理平台方案

在智能仓储、物流配送、智能制造等领域&#xff0c;立体仓库堆垛机是实现货物自动化存取、提升仓储效率与空间利用率的核心装备。其主要功能是在立体货架间进行精准、高效的货物搬运与定位&#xff0c;以支持现代物流系统的高周转与高精度需求。随着仓储自动化与数字化水平的不…

mqtt之轻量级客户端协议源码实现(方便移植,亲测好用)

// mqtt_tiny.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 //#include <iostream>#include "mqttclient.h" #include <windows.h> #include <conio.h>static void mqtt_message_cb(void* client, const char* topic, …

能源化工行业,PHP大文件上传与断点续传的解决方案?

开发者日记&#xff1a;2024年X月X日 星期X 长沙 阴 项目背景 今日正式接手客户的大文件传输系统外包项目&#xff0c;需求明确&#xff1a;支持20G文件/文件夹上传下载、跨平台&#xff08;Windows/macOS/Linux&#xff09;、全浏览器兼容&#xff08;含IE8&#xff09;、断点…

MySQL数据可视化实战技巧

数据可视化基础与MySQL的结合数据可视化的定义与重要性MySQL在数据处理中的角色常见数据可视化工具简介&#xff08;如Tableau、Power BI、Python库&#xff09;MySQL数据准备与清洗数据库连接与数据查询基础&#xff08;SELECT语句&#xff09;数据清洗技巧&#xff08;处理NU…

数据 “开口说话”!虎贲等考 AI 数据分析功能解锁论文实证新姿势

还在对着一堆调研数据无从下手&#xff1f;还在为 SPSS 操作界面抓狂到脱发&#xff1f;还在因图表不规范被导师连环批注&#xff1f;作为深耕论文写作科普的博主&#xff0c;后台每天都被科研党和毕业生的数据分析难题刷屏。别慌&#xff01;虎贲等考 AI 智能写作平台&#xf…

Elasticsearch Swarm 单机部署和测试流程

文章目录 📁 项目结构规划 📦 第一步:创建项目目录和文件 ⚙️ 第二步:创建配置文件 1. 创建 docker-compose.yml 2. 创建 Elasticsearch 自定义配置 3. 创建环境变量文件 🚀 第三步:创建部署脚本 1. 部署脚本 2. 测试脚本 3. 清理脚本 📄 第四步:创建使用说明 快速…

Google AI Studio+Gemini Pro:小白也能驾驭的AI魔法组合

引言 在当今这个 AI 技术飞速发展的时代,人工智能的应用已经渗透到了我们生活和工作的各个角落。从智能语音助手到图像识别技术,从自动化客服到智能驾驶,AI 的强大功能让我们的生活变得更加便捷和高效。其中,谷歌的 Gemini Pro 模型以其卓越的性能和广泛的应用场景,成为了…

TCP/IP协议栈:从原理到实战全解析

TCP/IP协议栈深度解析技术文章大纲协议栈概述TCP/IP协议栈的分层结构&#xff08;四层或五层模型&#xff09;与OSI七层模型的对比协议栈的核心设计思想网络接口层&#xff08;链路层&#xff09;以太网、Wi-Fi等底层协议的作用MAC地址与ARP协议解析数据帧的封装与解封装网络层…

突破限制:巧用Azure OpenAI,畅玩Gemini模型

引言 在人工智能飞速发展的当下,Gemini 模型凭借其强大的语言理解与生成能力,吸引了众多开发者的目光。然而,国内的网络环境使得直接访问 Gemini 模型困难重重,“魔法” 手段不仅操作复杂,还存在诸多风险。幸运的是,我们可以通过 Azure OpenAI 服务这一巧妙的途径,间接调…

【Python高级编程】辅助教师教学工具:PTA 成绩统计小程序

目录 一、引言 二、开发起点&#xff1a;需求挖掘与场景分析 三、方案设计&#xff1a;技术选型与架构规划 四、核心开发阶段&#xff1a;从 “能用” 到 “好用” 1. 基础能力搭建&#xff1a;先确保 “能读文件、能操作” 2. 核心逻辑开发&#xff1a;解决 “统计” 的…

解锁Gemini:Firebase平台合规调用AI模型实战全攻略

一、引言 在人工智能飞速发展的当下,Gemini 凭借其卓越的性能,成为众多开发者关注的焦点。作为谷歌旗下先进的 AI 模型,Gemini 在自然语言处理、图像识别等多领域展现出强大的能力,为开发者们打开了全新的应用开发思路。而 Firebase 作为谷歌提供的一套功能全面的后端即服务…

将本地代码推送到 GitHub 的方法

目录 一、准备工作 二、首次推送&#xff08;本地代码→新 GitHub 仓库&#xff09; 三、后续推送&#xff08;本地代码更新后→GitHub&#xff09; 四、常见问题及解决 五、总结 一、准备工作 安装 Git&#xff1a;从https://git-scm.com/下载并安装&#xff0c;安装后右…

亲测好用8个AI论文工具,助本科生轻松搞定毕业论文!

亲测好用8个AI论文工具&#xff0c;助本科生轻松搞定毕业论文&#xff01; AI 工具如何助力论文写作&#xff1f; 在当今信息爆炸的时代&#xff0c;撰写一篇高质量的毕业论文对于本科生来说&#xff0c;既是一次学术能力的考验&#xff0c;也是一场与时间赛跑的挑战。面对繁重…

汇川md380量产参考方案,包括原理图、PCB设计图及矢量源码:现成解决方案,轻松量产学习利器

汇川频器md380量产方案&#xff0c;包含原理图&#xff0c;pcb图&#xff0c;矢量源码。 拿来就用&#xff01;量产参考&#xff0c;学习提高&#xff0c;必备利器。MD380量产方案的硬件设计核心在电源模块和驱动电路。原理图里的三相整流部分用了六个二极管搭成全桥结构&#…