sudo-iのBlog

  • 🍟首页
  • 🍊目录
    • 技术分享
    • vps教程
    • 软件分享
    • 干货分享
  • 🍎链接
  • 🍓工具
    • 🌽IP路由追踪
    • 域名被墙检测
    • KMS激活
    • 域名whois查询
  • 🍕联系
  • 🍌登录
Sudo-i
关注互联网,生活,音乐,乐此不疲
  1. 首页
  2. 干货分享
  3. 正文

MySQL 数据库性能优化实战:从 10 秒到 100 毫秒的蜕变

8 3 月, 2026 51点热度 0人点赞 0条评论

MySQL 数据库性能优化实战:从 10 秒到 100 毫秒的蜕变

在生产环境中,数据库性能问题往往是系统瓶颈的核心。本文将通过真实案例,带你掌握 MySQL 性能优化的核心技巧,让你的查询速度提升 100 倍。

一、性能问题诊断

优化之前,先学会诊断。以下是定位慢查询的关键方法:

1.1 开启慢查询日志

-- 查看慢查询配置
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

-- 临时开启慢查询日志
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;  -- 记录超过 1 秒的查询

-- 永久配置(my.cnf)
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = 1

1.2 分析慢查询日志

# 使用 mysqldumpslow 分析
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

# 使用 pt-query-digest(Percona Toolkit)
pt-query-digest /var/log/mysql/slow.log > /tmp/slow_analysis.txt

二、索引优化策略

索引是性能优化的第一道防线。正确的索引设计可以让查询速度提升几个数量级。

2.1 理解索引类型

-- B-Tree 索引(最常用)
CREATE INDEX idx_user_email ON users(email);

-- 联合索引(注意最左前缀原则)
CREATE INDEX idx_name_age ON users(name, age);

-- 覆盖索引(避免回表)
SELECT id, name FROM users WHERE name = '张三';  -- 如果 idx_name 存在

-- 全文索引(文本搜索)
ALTER TABLE articles ADD FULLTEXT INDEX ft_content (content);

2.2 索引优化实战

-- 场景:查询订单表中某个用户的最近订单
-- ❌ 慢查询(全表扫描)
SELECT * FROM orders WHERE user_id = 123 ORDER BY created_at DESC LIMIT 10;

-- ✅ 优化:创建联合索引
CREATE INDEX idx_user_created ON orders(user_id, created_at DESC);

-- 使用 EXPLAIN 分析执行计划
EXPLAIN SELECT * FROM orders WHERE user_id = 123 ORDER BY created_at DESC LIMIT 10;
-- 关注:type(ref 优于 all)、key(使用的索引)、rows(扫描行数)

2.3 索引使用陷阱

-- ❌ 索引失效的常见场景

-- 1. 对索引列使用函数
SELECT * FROM users WHERE DATE(created_at) = '2026-03-08';  -- 索引失效
SELECT * FROM users WHERE created_at >= '2026-03-08' AND created_at < '2026-03-09';  -- 索引生效

-- 2. 隐式类型转换
SELECT * FROM users WHERE phone = 13800138000;  -- phone 是 VARCHAR,数字会触发转换
SELECT * FROM users WHERE phone = '13800138000';  -- 正确

-- 3. LIKE 以通配符开头
SELECT * FROM users WHERE name LIKE '%张%';  -- 索引失效
SELECT * FROM users WHERE name LIKE '张%';  -- 索引生效

-- 4. OR 条件中部分列无索引
SELECT * FROM users WHERE email = 'test@example.com' OR phone = '13800138000';  -- 如果 phone 无索引,全表扫描

三、查询语句优化

3.1 SELECT 优化原则

-- ❌ 避免 SELECT *
SELECT * FROM users WHERE id = 1;

-- ✅ 只取需要的列
SELECT id, name, email FROM users WHERE id = 1;

-- ❌ 避免在 WHERE 子句中使用计算
SELECT * FROM orders WHERE YEAR(created_at) = 2026;

-- ✅ 使用范围查询
SELECT * FROM orders WHERE created_at >= '2026-01-01' AND created_at < '2027-01-01';

3.2 JOIN 优化

-- 小表驱动大表原则
-- 假设 users 表 1 万行,orders 表 100 万行

-- ✅ 推荐:小表在左
SELECT * FROM users u 
LEFT JOIN orders o ON u.id = o.user_id 
WHERE u.status = 1;

-- 确保 JOIN 列有索引
CREATE INDEX idx_orders_user_id ON orders(user_id);

3.3 分页优化

-- ❌ 深分页性能差(需要扫描前 100000 行)
SELECT * FROM orders ORDER BY created_at DESC LIMIT 100000, 10;

-- ✅ 方案 1:使用子查询(覆盖索引)
SELECT * FROM orders o
INNER JOIN (
    SELECT id FROM orders ORDER BY created_at DESC LIMIT 100000, 10
) tmp ON o.id = tmp.id;

-- ✅ 方案 2:使用游标分页(推荐)
SELECT * FROM orders 
WHERE created_at < '2026-03-01 00:00:00' 
ORDER BY created_at DESC LIMIT 10;

四、表结构优化

4.1 数据类型选择

-- 选择合适的数据类型
CREATE TABLE users (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,  -- 不用 INT,预留增长空间
    name VARCHAR(50) NOT NULL,  -- 不用 TEXT,长度固定用 VARCHAR
    email VARCHAR(100) NOT NULL,
    status TINYINT NOT NULL DEFAULT 1,  -- 状态用 TINYINT
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    
    INDEX idx_email (email),
    INDEX idx_status_created (status, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

4.2 表分区

-- 按时间范围分区(适合日志、订单表)
ALTER TABLE orders PARTITION BY RANGE (YEAR(created_at)) (
    PARTITION p2024 VALUES LESS THAN (2025),
    PARTITION p2025 VALUES LESS THAN (2026),
    PARTITION p2026 VALUES LESS THAN (2027),
    PARTITION pmax VALUES LESS THAN MAXVALUE
);

-- 查询时自动分区裁剪
SELECT * FROM orders WHERE created_at >= '2026-01-01';  -- 只扫描 p2026 分区

五、配置参数调优

[mysqld]
# 内存相关(根据服务器内存调整)
innodb_buffer_pool_size = 4G  # 物理内存的 50-70%
innodb_log_file_size = 512M
innodb_log_buffer_size = 64M

# 连接数
max_connections = 500
thread_cache_size = 100

# 查询缓存(MySQL 5.7,8.0 已移除)
query_cache_size = 64M
query_cache_type = 1

# InnoDB 相关
innodb_flush_log_at_trx_commit = 2  # 1 最安全,2 性能好,0 最快但不安全
innodb_flush_method = O_DIRECT
innodb_io_capacity = 2000

# 日志
slow_query_log = 1
long_query_time = 1

六、实战案例:优化前后对比

优化前

-- 查询用户订单统计
SELECT u.id, u.name, COUNT(o.id) as order_count, SUM(o.amount) as total_amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.status = 1
GROUP BY u.id, u.name
HAVING order_count > 5
ORDER BY total_amount DESC
LIMIT 100;

-- 执行时间:12.5 秒
-- 扫描行数:500 万

优化后

-- 1. 添加索引
CREATE INDEX idx_users_status ON users(status);
CREATE INDEX idx_orders_user_amount ON orders(user_id, amount);

-- 2. 优化查询(使用物化视图思想)
CREATE TABLE user_order_stats (
    user_id BIGINT PRIMARY KEY,
    order_count INT,
    total_amount DECIMAL(10,2),
    updated_at TIMESTAMP
);

-- 定期更新统计表
INSERT INTO user_order_stats 
SELECT u.id, COUNT(o.id), SUM(o.amount), NOW()
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.status = 1
GROUP BY u.id
ON DUPLICATE KEY UPDATE 
    order_count = VALUES(order_count),
    total_amount = VALUES(total_amount),
    updated_at = NOW();

-- 3. 查询统计表
SELECT u.id, u.name, s.order_count, s.total_amount
FROM users u
JOIN user_order_stats s ON u.id = s.user_id
WHERE u.status = 1 AND s.order_count > 5
ORDER BY s.total_amount DESC
LIMIT 100;

-- 执行时间:0.08 秒
-- 扫描行数:1 万
-- 性能提升:156 倍

七、监控与持续优化

-- 实时监控关键指标
SHOW STATUS LIKE 'Threads_connected';  -- 当前连接数
SHOW STATUS LIKE 'Innodb_buffer_pool_wait_free';  -- 缓冲池等待
SHOW STATUS LIKE 'Handler_read_rnd_next';  -- 全表扫描次数

-- 查看当前正在执行的查询
SHOW PROCESSLIST;

-- 查看表大小和行数
SELECT table_name, table_rows, data_length, index_length
FROM information_schema.tables 
WHERE table_schema = 'your_database'
ORDER BY data_length DESC;

总结

MySQL 性能优化是一个系统工程,需要从多个维度入手:

  1. 诊断先行:慢查询日志 + EXPLAIN 是必备工具
  2. 索引为王:正确的索引设计解决 80% 的性能问题
  3. 查询优化:避免常见陷阱,遵循最佳实践
  4. 架构设计:合理的表结构和分区策略
  5. 参数调优:根据实际负载调整配置
  6. 持续监控:性能优化是持续过程

记住:没有银弹,只有针对具体场景的最优解。每次优化前,先测量;优化后,再验证。

无关联文章

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: 暂无
最后更新:8 3 月, 2026

李炫炫

这个人很懒,什么都没留下

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

COPYRIGHT © 2025 sudo-iのBlog. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

鲁ICP备2024054662号

鲁公网安备37108102000450号