MySQL 数据库性能优化是提升应用性能的关键。本文将全面介绍 MySQL 的优化技巧,从索引优化、查询优化到配置优化,帮助你构建高性能的数据库系统。
一、数据库性能优化概述
1.1 性能优化的目标
提高查询速度:减少查询执行时间
提高写入速度:优化数据写入性能
降低资源消耗:减少 CPU、内存、磁盘使用
提高并发能力:支持更多并发请求
1.2 性能优化方法
查询优化:优化 SQL 查询语句
索引优化:创建合适的索引
表结构优化:优化表结构设计
配置优化:调整数据库配置
架构优化:使用缓存、读写分离等
二、索引优化
2.1 什么是索引?
索引是数据库表中的一种数据结构,类似于书的目录,可以快速定位数据,提高查询速度。
2.2 创建索引
-- 为单列创建索引 CREATE INDEX idx_user_name ON users(name);
-- 为多列创建联合索引 CREATE INDEX idx_user_name_age ON users(name, age);
-- 唯一索引 CREATEUNIQUE INDEX idx_user_email ON users(email);
-- 全文索引 CREATE FULLTEXT INDEX idx_article_content ON articles(content);
2.3 索引类型
-- 主键索引(默认) ALTERTABLE users ADDPRIMARY KEY (id);
-- 唯一索引 CREATEUNIQUE INDEX idx_username ON users(username);
-- 普通索引 CREATE INDEX idx_age ON users(age);
-- 联合索引 CREATE INDEX idx_name_email ON users(name, email);
-- 全文索引 CREATE FULLTEXT INDEX idx_content ON articles(content);
2.4 索引优化原则
最左前缀原则
-- 创建联合索引 CREATE INDEX idx_name_age ON users(name, age);
-- 好的查询(使用最左前缀) SELECT*FROM users WHERE name ='张三'; SELECT*FROM users WHERE name ='张三'AND age =25;
-- 不好的查询(跳过第一列) SELECT*FROM users WHERE age =25; -- 不使用索引
-- 不好的查询(顺序不对) SELECT*FROM users WHERE age =25AND name ='张三'; -- 不使用索引
最小索引列数
-- 不好的做法(创建了过多索引) CREATE INDEX idx_name ON users(name); CREATE INDEX idx_age ON users(age); CREATE INDEX idx_email ON users(email); CREATE INDEX idx_name_age ON users(name, age); CREATE INDEX idx_name_email ON users(name, email);
-- 好的做法(使用联合索引) CREATE INDEX idx_name_age_email ON users(name, age, email);
避免冗余索引
-- 冗余索引 CREATE INDEX idx_name ON users(name); CREATE INDEX idx_name_age ON users(name, age);
-- 查询分析 EXPLAIN SELECT*FROM users WHERE name ='张三'AND age =25; -- idx_name_age 会使用,idx_name 不会被使用
2.5 索引维护
-- 查看索引使用情况 SHOW INDEX FROM users;
-- 分析表 ANALYZE TABLE users;
-- 优化表 OPTIMIZE TABLE users;
-- 删除无用索引 DROP INDEX idx_name ON users;
-- 查看索引大小 SELECT table_name, index_name, ROUND(stat_value * @@innodb_page_size/1024/1024, 2) AS size_mb FROM mysql.innodb_index_stats WHERE table_name ='users'AND database_name ='your_db';
2.6 索引最佳实践
-- 为 WHERE、ORDER BY、GROUP BY 使用索引 -- 好的查询(使用索引) SELECT*FROM users WHERE name ='张三'ORDERBY age; SELECT*FROM users WHERE age =25ORDERBY name;
-- 不好的查询(不使用索引) SELECT*FROM users ORDERBY name; -- 应该在 name 上创建索引
三、查询优化
3.1 避免 SELECT *
-- 不好的做法(获取所有列) SELECT*FROM users WHERE age =25;
-- 好的做法(只获取需要的列) SELECT id, name, email FROM users WHERE age =25;
3.2 使用 LIMIT
-- 不好的做法(查询所有数据) SELECT*FROM users;
-- 好的做法(分页查询) SELECT*FROM users LIMIT 10;
-- 分页优化 SELECT*FROM users WHERE id > last_id ORDERBY id LIMIT 10;
3.3 使用 EXPLAIN 分析查询
-- 分析查询执行计划 EXPLAIN SELECT*FROM users WHERE name ='张三';
-- 按日期分区 ALTERTABLE orders PARTITIONBYRANGE (YEAR(create_time)) ( PARTITION p2020 VALUES LESS THAN (2021), PARTITION p2021 VALUES LESS THAN (2022), PARTITION p2022 VALUES LESS THAN (2023), PARTITION pmax VALUES LESS THAN MAXVALUE );
-- 复杂查询示例 SELECT u.name, u.email, COUNT(o.id) AS order_count, SUM(o.amount) AS total_amount FROM users u LEFTJOIN orders o ON u.id = o.user_id WHERE u.age >=18 GROUPBY u.id, u.name, u.email HAVING order_count >0 ORDERBY total_amount DESC LIMIT 20;
6.2 使用索引优化
-- 查看索引使用情况 EXPLAIN SELECT*FROM users WHERE name ='张三'AND age =25;