MySQL性能优化

掌握查询优化、索引优化和服务器配置技巧

MySQL性能优化概述

MySQL性能优化是一个系统性的工作,涉及查询优化、索引优化、服务器配置优化、架构设计优化等多个方面。

性能优化的目标

  • 提高查询响应速度
  • 减少服务器资源消耗
  • 提高系统并发处理能力
  • 确保系统稳定性和可扩展性

查询优化

使用EXPLAIN分析查询

SQL示例
EXPLAIN SELECT * FROM orders 
WHERE customer_id = 123 AND order_date > '2024-01-01';

EXPLAIN输出关键字段

字段 描述 优化建议
type 连接类型 避免ALL(全表扫描),追求const、eq_ref、ref
key 实际使用的索引 确保查询使用了合适的索引
rows 预估扫描行数 行数越少越好
Extra 额外信息 避免Using filesort、Using temporary

避免SELECT *

SQL示例
-- 不推荐的写法
SELECT * FROM customers;

-- 推荐的写法
SELECT customer_id, first_name, last_name, email 
FROM customers;

使用LIMIT限制结果集

SQL示例
-- 限制返回的记录数
SELECT * FROM products 
ORDER BY created_at DESC
LIMIT 10;

避免在WHERE子句中使用函数

SQL示例
-- 不推荐的写法(无法使用索引)
SELECT * FROM orders 
WHERE YEAR(order_date) = 2024;

-- 推荐的写法
SELECT * FROM orders 
WHERE order_date >= '2024-01-01' AND order_date < '2025-01-01';

索引优化

选择合适的索引列

  • WHERE子句中的列
  • JOIN连接条件的列
  • ORDER BY和GROUP BY中的列
  • 选择性高的列(唯一值多的列)

复合索引的最左前缀原则

SQL示例
-- 创建复合索引
CREATE INDEX idx_last_first ON customers(last_name, first_name);

-- 可以使用索引的查询
SELECT * FROM customers WHERE last_name = 'Smith';
SELECT * FROM customers WHERE last_name = 'Smith' AND first_name = 'John';

-- 不能使用索引的查询
SELECT * FROM customers WHERE first_name = 'John';

覆盖索引

SQL示例
-- 创建覆盖索引
CREATE INDEX idx_customer_info ON customers(last_name, first_name, email);

-- 查询可以直接从索引中获取数据,无需访问表
SELECT last_name, first_name, email FROM customers 
WHERE last_name = 'Smith';

表结构优化

选择合适的数据类型

  • 使用最小的数据类型
  • 避免使用TEXT/BLOB类型,除非必要
  • 使用INT而不是VARCHAR存储数字
  • 使用ENUM代替VARCHAR存储固定值

规范化与反规范化的平衡

规范化:减少数据冗余,提高数据一致性,但可能增加查询复杂度。
反规范化:增加数据冗余,减少表连接,提高查询性能。

分区表

SQL示例
-- 按范围分区
CREATE TABLE sales (
    sale_id INT,
    sale_date DATE,
    amount DECIMAL(10,2)
)
PARTITION BY RANGE (YEAR(sale_date)) (
    PARTITION p2020 VALUES LESS THAN (2021),
    PARTITION p2021 VALUES LESS THAN (2022),
    PARTITION p2022 VALUES LESS THAN (2023),
    PARTITION p2023 VALUES LESS THAN (2024)
);

服务器配置优化

关键配置参数

参数 描述 建议值
innodb_buffer_pool_size InnoDB缓冲池大小 物理内存的50-80%
innodb_log_file_size 重做日志文件大小 1-4GB
max_connections 最大连接数 根据应用需求调整
query_cache_size 查询缓存大小 MySQL 8.0已移除

监控服务器状态

SQL示例
-- 查看服务器状态
SHOW STATUS LIKE 'Threads_connected';
SHOW STATUS LIKE 'Innodb_buffer_pool_reads';

-- 查看进程列表
SHOW PROCESSLIST;

-- 查看慢查询
SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'long_query_time';

架构优化

读写分离

将读操作和写操作分发到不同的数据库服务器:

  • 主服务器处理写操作
  • 从服务器处理读操作
  • 通过主从复制保持数据同步

分库分表

当单表数据量过大时,可以考虑分库分表:

  • 水平分表:按数据行拆分
  • 垂直分表:按列拆分
  • 分库:将不同业务的数据分布到不同数据库

使用缓存

  • 应用层缓存(Redis、Memcached)
  • 数据库查询缓存(MySQL 8.0之前)
  • CDN缓存静态资源
优化原则:性能优化是一个持续的过程,需要根据实际业务需求和数据特征进行调整。测量、分析、优化、再测量。

性能监控工具

使用专业的监控工具可以帮助识别性能瓶颈:

MySQL内置工具

  • SHOW STATUS - 查看服务器状态变量
  • SHOW PROCESSLIST - 查看当前连接和查询
  • EXPLAIN - 分析查询执行计划
  • Performance Schema - 性能模式,收集数据库性能数据
  • Information Schema - 信息模式,查看数据库元数据

外部监控工具

  • MySQL Enterprise Monitor - MySQL官方企业级监控工具
  • Percona Monitoring and Management - Percona监控管理工具
  • Prometheus + Grafana - 开源监控解决方案
  • pt-query-digest - Percona Toolkit中的查询分析工具

慢查询日志分析

慢查询日志是识别性能问题的重要工具:

启用慢查询日志

my.cnf 配置
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
log_queries_not_using_indexes = 1

分析慢查询日志

终端命令
# 使用mysqldumpslow分析慢查询日志
mysqldumpslow /var/log/mysql/slow.log

# 使用pt-query-digest分析慢查询日志
pt-query-digest /var/log/mysql/slow.log

查询缓存优化

虽然MySQL 8.0移除了查询缓存,但在早期版本中仍可使用:

查询缓存配置

my.cnf 配置
[mysqld]
query_cache_type = 1
query_cache_size = 64M
query_cache_limit = 2M

查询缓存状态监控

SQL示例
-- 查看查询缓存状态
SHOW STATUS LIKE 'Qcache%';

连接池优化

使用连接池可以减少连接建立和关闭的开销:

连接池配置

  • 设置合适的最大连接数
  • 设置连接超时时间
  • 定期检查连接有效性
  • 使用连接池监控工具

下一步学习

掌握了性能优化知识后,您可以继续学习: