以下是 MySQL优化方式及用例**,涵盖索引、查询、表设计、配置、架构、开发规范等多个方向,结合实际应用场景举例说明:
---
一、索引优化
1. **单列索引**
**用例**:为高频查询字段(如用户表的 `user_id`)建立索引。
```sql
CREATE INDEX idx_user_id ON users(user_id);
```
2. **联合索引(最左前缀)**
**用例**:查询条件常同时使用 `status` 和 `create_time` 时,建立联合索引。
```sql
CREATE INDEX idx_status_time ON orders(status, create_time);
```
3. **覆盖索引**
**用例**:查询仅需索引字段时,避免回表。
```sql
-- 索引 (product_id, price)
SELECT product_id, price FROM products WHERE product_id = 100;
```
4. **避免冗余索引**
**用例**:已有 `(a, b)` 索引时,不再单独创建 `(a)` 索引。
5. **索引下推(ICP)**
**用例**:MySQL 5.6+ 支持在存储引擎层过滤数据。
```sql
-- 索引 (age, city)
SELECT * FROM users WHERE age > 20 AND city = 'Beijing';
```
6. **前缀索引**
**用例**:对长文本字段(如 `VARCHAR(255)`)取前N个字符建索引。
```sql
CREATE INDEX idx_email_prefix ON users(email(10));
```
7. **函数索引(MySQL 8.0+)**
**用例**:针对JSON字段或计算字段建立索引。
```sql
CREATE INDEX idx_name_lower ON users((LOWER(name)));
```
8. **唯一索引**
**用例**:确保字段唯一性(如手机号、邮箱)。
```sql
CREATE UNIQUE INDEX idx_unique_phone ON customers(phone);
```
9. **全文索引**
**用例**:支持文本搜索(如文章内容)。
```sql
CREATE FULLTEXT INDEX idx_content ON articles(content);
```
10. **空间索引**
**用例**:地理位置查询(如经纬度范围)。
```sql
CREATE SPATIAL INDEX idx_location ON places(coordinates);
```
11. **索引选择性**
**用例**:选择性高的字段(如唯一值多的字段)优先建索引。
12. **隐藏索引(MySQL 8.0+)**
**用例**:测试删除索引后的性能影响,无需真正删除。
```sql
ALTER TABLE users ALTER INDEX idx_age INVISIBLE;
```
13. **降序索引**
**用例**:优化 `ORDER BY column DESC` 查询。
```sql
CREATE INDEX idx_time_desc ON logs(create_time DESC);
```
14. **索引合并**
**用例**:多个单列索引的组合使用(需评估是否应建联合索引)。
```sql
-- 使用索引 idx_a 和 idx_b
SELECT * FROM table WHERE a = 1 OR b = 2;
```
15. **使用索引提示**
**用例**:强制指定查询使用的索引。
```sql
SELECT * FROM users USE INDEX (idx_email) WHERE email = '[email protected]';
```
16. **避免索引列计算**
**用例**:避免在索引字段上使用函数或计算。
```sql
-- 错误:WHERE YEAR(create_time) = 2023
-- 正确:WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31'
```
17. **索引碎片整理**
**用例**:定期重建索引提升性能。
```sql
OPTIMIZE TABLE users;
```
18. **区分度低的字段不建索引**
**用例**:如性别字段(只有男/女)无需单独建索引。
19. **外键索引**
**用例**:外键字段必须建索引以保证关联效率。
```sql
ALTER TABLE orders ADD INDEX fk_user_id (user_id);
```
20. **虚拟列索引(MySQL 5.7+)**
**用例**:为生成列建立索引。
```sql
ALTER TABLE products ADD COLUMN price_tax INT AS (price * 1.1);
CREATE INDEX idx_price_tax ON products(price_tax);
```
---
二、查询优化
21. **避免 `SELECT *`**
**用例**:仅查询必要字段。
```sql
SELECT id, name FROM users WHERE age > 18;
```
22. **分页优化(延迟关联)**
**用例**:百万级数据分页时先查ID,再关联原表。
```sql
SELECT * FROM users INNER JOIN (
SELECT id FROM users ORDER BY create_time LIMIT 1000000, 10
) AS tmp USING(id);
```
23. **`EXISTS` 替代 `IN`**
**用例**:子查询结果集大时用 `EXISTS` 更高效。
```sql
SELECT * FROM users u WHERE EXISTS (
SELECT 1 FROM orders o WHERE o.user_id = u.id
);
```
24. **`UNION ALL` 替代 `UNION`**
**用例**:不需要去重时用 `UNION ALL` 减少开销。
25. **避免 `OR` 条件**
**用例**:将 `OR` 改写为 `UNION`。
```sql
SELECT * FROM users WHERE age < 18
UNION
SELECT * FROM users WHERE age > 60;
```
26. **`JOIN` 字段类型一致**
**用例**:确保关联字段类型一致,避免隐式转换。
```sql
-- users.id 是 INT,orders.user_id 也应为 INT
SELECT * FROM users JOIN orders ON users.id = orders.user_id;
```
27. **小表驱动大表**
**用例**:`JOIN` 时小表放在前面。
```sql
SELECT * FROM small_table s JOIN large_table l ON s.id = l.s_id;
```
28. **避免子查询中的 `ORDER BY`**
**用例**:外层查询排序更高效。
```sql
-- 错误:SELECT * FROM (SELECT * FROM users ORDER BY id) AS t
-- 正确:SELECT * FROM users ORDER BY id;
```
29. **使用 `LIMIT` 提前终止查询**
**用例**:仅需部分结果时加 `LIMIT`。
```sql
SELECT * FROM logs WHERE error_code = 500 LIMIT 1;
```
30. **避免 `HAVING` 过滤**
**用例**:优先用 `WHERE` 过滤数据。
```sql
-- 错误:SELECT user_id, COUNT(*) FROM orders GROUP BY user_id HAVING user_id > 100
-- 正确:SELECT user_id, COUNT(*) FROM orders WHERE user_id > 100 GROUP BY user_id
```
31. **利用 `STRAIGHT_JOIN` 强制连接顺序**
**用例**:手动指定 `JOIN` 顺序优化复杂查询。
```sql
SELECT STRAIGHT_JOIN a.*, b.* FROM a JOIN b ON a.id = b.a_id;
```
32. **使用临时表缓存中间结果**
**用例**:复杂查询分步执行。
```sql
CREATE TEMPORARY TABLE tmp_users SELECT id FROM users WHERE age > 18;
SELECT * FROM tmp_users JOIN orders ON tmp_users.id = orders.user_id;
```
33. **`FORCE INDEX` 强制使用索引**
**用例**:优化器未选择最优索引时手动指定。
```sql
SELECT * FROM users FORCE INDEX (idx_age) WHERE age BETWEEN 20 AND 30;
```
34. **避免 `DISTINCT`**
**用例**:用 `GROUP BY` 替代 `DISTINCT`。
```sql
-- 错误:SELECT DISTINCT user_id FROM orders
-- 正确:SELECT user_id FROM orders GROUP BY user_id
```
35. **使用 `BETWEEN` 替代范围查询**
**用例**:明确范围时更高效。
```sql
SELECT * FROM logs WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31';
```
36. **`COUNT(*)` 替代 `COUNT(column)`**
**用例**:统计行数时用 `COUNT(*)` 更快。
37. **避免 `NOT IN`**
**用例**:改用 `LEFT JOIN` 或 `NOT EXISTS`。
```sql
SELECT * FROM users u WHERE NOT EXISTS (
SELECT 1 FROM banned_users b WHERE b.user_id = u.id
);
```
38. **`GROUP BY` 优化**
**用例**:`GROUP BY` 字段顺序与索引一致。
```sql
-- 索引 (category, status)
SELECT category, status, COUNT(*) FROM products GROUP BY category, status;
```
39. **`ORDER BY NULL` 禁用排序**
**用例**:`GROUP BY` 后无需排序时提升性能。
```sql
SELECT category, COUNT(*) FROM products GROUP BY category ORDER BY NULL;
```
40. **批量插入优化**
**用例**:单条 `INSERT` 插入多行数据。
```sql
INSERT INTO users (name, age) VALUES ('Alice', 25), ('Bob', 30);
```
---
三、表结构优化 (15种)
41. **选择合适的数据类型**
**用例**:用 `INT` 存储IP地址而非 `VARCHAR`。
```sql
INET_ATON('192.168.1.1') -- 转换为整数
```
42. **垂直分表**
**用例**:将大字段(如 `TEXT`)拆分到副表。
```sql
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(100),
detail_id INT
);
CREATE TABLE product_details (
id INT PRIMARY KEY,
description TEXT
);
```
43. **水平分表**
**用例**:按用户ID哈希分表。
```sql
-- 分表规则:user_id % 10 → 10张表
CREATE TABLE users_0 (id INT PRIMARY KEY, ...);
CREATE TABLE users_1 (id INT PRIMARY KEY, ...);
```
44. **使用分区表**
**用例**:按时间范围分区。
```sql
CREATE TABLE logs (
id INT,
log_time DATETIME
) PARTITION BY RANGE (YEAR(log_time)) (
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025)
);
```
45. **字段默认值**
**用例**:避免 `NULL`,设置默认值。
```sql
ALTER TABLE users MODIFY age INT DEFAULT 0;
```
46. **压缩表**
**用例**:对静态大表启用压缩。
```sql
CREATE TABLE logs ( ... ) ROW_FORMAT=COMPRESSED;
```
47. **使用枚举类型**
**用例**:有限值的字段(如状态)用 `ENUM`。
```sql
CREATE TABLE orders (
status ENUM('pending', 'completed', 'cancelled')
);
```
48. **避免 `TEXT/BLOB` 频繁更新**
**用例**:将大字段单独存表,减少主表IO。
49. **适当冗余字段**
**用例**:减少 `JOIN` 查询,如订单表冗余用户名。
50. **控制表宽度**
**用例**:单行数据不宜过宽(如不超过8KB)。
51. **使用生成列(MySQL 5.7+)**
**用例**:自动计算字段值。
```sql
ALTER TABLE products ADD COLUMN total_price INT AS (price * quantity);
```
52. **删除无用索引**
**用例**:定期分析索引使用情况,删除未使用索引。
53. **使用 `CHAR` 定长字段**
**用例**:存储固定长度数据(如MD5哈希值)。
```sql
password CHAR(32) -- 存储MD5
```
54. **避免过多列**
**用例**:单表字段数建议不超过50个。
55. **归档历史数据**
**用例**:将旧数据迁移到归档表,减少主表体积。
---
四、配置优化
56. **调整 `innodb_buffer_pool_size`**
**用例**:设置为物理内存的70%。
```ini
[mysqld]
innodb_buffer_pool_size = 16G
```
57. **设置 `innodb_flush_log_at_trx_commit=2`**
**用例**:牺牲部分持久性换取写入性能(适合日志类应用)。
58. **增大 `max_connections`**
**用例**:高并发场景增加连接数。
```ini
max_connections = 1000
```
59. **启用 `slow_query_log`**
**用例**:记录慢查询用于分析。
```ini
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
```
60. **调整 `tmp_table_size`**
**用例**:增大临时表内存分配。
```ini
tmp_table_size = 256M
max_heap_table_size = 256M
```
61. **关闭 `query_cache`(MySQL 8.0前)**
**用例**:高并发读写的场景关闭查询缓存。
```ini
query_cache_type = 0
```
62. **调整 `innodb_log_file_size`**
**用例**:增大Redo日志文件大小(如4GB)。
```ini
innodb_log_file_size = 4G
```
63. **设置 `innodb_io_capacity`**
**用例**:SSD硬盘提高IOPS设置。
```ini
innodb_io_capacity = 20000
```
64. **启用 `innodb_file_per_table`**
**用例**:每个InnoDB表使用独立表空间。
```ini
innodb_file_per_table = 1
```
65. **调整 `thread_cache_size`**
**用例**:减少线程创建开销。
```ini
thread_cache_size = 64
```
66. **配置 `read_buffer_size`**
**用例**:增大顺序扫描的缓冲区。
```ini
read_buffer_size = 2M
```
67. **设置 `innodb_flush_method=O_DIRECT`**
**用例**:避免双缓冲,提升写入性能。
68. **调整 `innodb_thread_concurrency`**
**用例**:控制InnoDB并发线程数。
```ini
innodb_thread_concurrency = 16
```
69. **启用 `innodb_stats_on_metadata=OFF`**
**用例**:避免统计信息更新影响性能。
70. **配置 `binlog_format=ROW`**
**用例**:主从复制时使用行模式保证数据一致性。
---
五、架构优化
71. **读写分离**
**用例**:使用ProxySQL或中间件将读请求路由到从库。
72. **分库分表(Sharding)**
**用例**:按用户ID哈希分库,解决单库性能瓶颈。
73. **使用缓存层(Redis)**
**用例**:缓存热点商品信息,减少数据库查询。
```python
# 伪代码示例
data = redis.get('product:100')
if not data:
data = db.query('SELECT * FROM products WHERE id = 100')
redis.set('product:100', data, ex=3600)
```
74. **异步写入**
**用例**:日志数据通过消息队列(如Kafka)异步入库。
75. **使用CDN加速静态资源**
**用例**:图片、视频等静态资源走CDN,减少数据库压力。
76. **冷热数据分离**
**用例**:将3个月前的订单数据迁移到历史库。
77. **主从延迟监控**
**用例**:使用 `SHOW SLAVE STATUS` 监控复制延迟。
78. **使用连接池**
**用例**:应用端配置连接池(如HikariCP),避免频繁创建连接。
79. **数据库代理(如MySQL Router)**
**用例**:自动路由请求到可用节点。
80. **多主复制(Multi-Source Replication)**
**用例**:聚合多个数据源到分析库。
81. **使用列式存储(如ClickHouse)**
**用例**:分析类查询迁移到列式数据库。
82. **地理分区部署**
**用例**:用户就近访问所在区域的数据中心。
83. **灾备与高可用(如MHA、InnoDB Cluster)**
**用例**:主库故障时自动切换到从库。
84. **使用内存数据库(如MemSQL)**
**用例**:实时分析场景替代MySQL。
85. **定期数据归档**
**用例**:将一年前的订单数据迁移到归档库。
---
### **六、开发规范优化 (15种)**
86. **禁止全表更新/删除**
**用例**:`UPDATE` 或 `DELETE` 必须带 `WHERE` 条件。
87. **统一事务范围**
**用例**:避免在事务中执行远程调用等耗时操作。
88. **避免隐式类型转换**
**用例**:确保传入参数类型与字段类型一致。
89. **使用预编译语句**