请关注—MySQL各种优化汇总一次性掌握

以下是 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. **使用预编译语句**  

 

你可能感兴趣的:(数据治理,mysql,数据库)