MYSQL优化器的主要的优化策略及其示例

MySQL 优化器除了 自动将 WHERE 条件前置(谓词下推,Predicate Pushdown) 之外,还会进行许多其他关键优化,以提高查询性能。以下是主要的优化策略及其示例:


1. 查询重写(Query Rewriting)

优化器会 重写 SQL,使其更高效,即便 SQL 写法不同,最终执行计划可能相同。

示例优化

  • IN → EXISTS / JOIN 转换

    sql 复制代码
    -- 原始语句
    SELECT * FROM users WHERE id IN (SELECT user_id FROM orders);
    
    -- 可能被优化为
    SELECT users.* FROM users JOIN orders ON users.id = orders.user_id;
  • OR 合并优化

    sql 复制代码
    -- 原始语句
    SELECT * FROM users WHERE age > 20 OR salary > 5000;
    
    -- 可能拆分成两个 Range Scan 并合并

2. 索引优化

优化器会 智能选择最佳索引 ,甚至 动态调整索引使用策略

示例优化

  1. 覆盖索引(Covering Index)

    • 如果可以,优化器会直接从索引读取数据,避免回表(减少 I/O)。
    sql 复制代码
    SELECT id, name FROM users WHERE age = 25;
    -- 如果 (age, id, name) 构成覆盖索引,就不读表数据
  2. Index Skip Scan(MySQL 8.0+)

    • 对复合索引 (a, b),即使 a 未指定,也能利用 b 的部分扫描。
  3. Multi-Range Read (MRR)

    • 先收集 所有满足 WHERE 条件的 id,再按主键排序读取数据(减少随机 I/O)。
  4. Index Condition Pushdown (ICP, 索引条件下推)

    • 让存储引擎 在索引层过滤数据 (减少回表次数)。
    sql 复制代码
    -- 复合索引 (name, age)
    SELECT * FROM users WHERE name LIKE '张%' AND age > 20;
    -- ICP 让存储引擎直接过滤 age > 20,避免回表

3. 连接优化(Join Optimizations)

优化器会 调整 JOIN 顺序、方式,减少计算量。

示例优化

  1. JOIN 顺序优化

    • 小表优先 JOIN(减少中间结果)。
    sql 复制代码
    SELECT * FROM large_table JOIN small_table ON ...;
    -- 优化器可能会自动先处理 small_table
  2. 使用 Batched Key Access (BKA)

    • 减少 JOIN 时的随机 I/O(结合 MRR)。
  3. Hash Join / Nested Loop Join 选择

    • MySQL 8.0+ 支持 Hash Join(适合无索引大表 JOIN 时)。
  4. 子查询优化(Subquery Materialization)

    • IN (...) 子查询可能被 物化(临时表缓存),避免重复计算。
  5. 外连接转内连接(OUTER JOIN → INNER JOIN)

    sql 复制代码
    SELECT * FROM users LEFT JOIN orders ON users.id = orders.user_id
    WHERE orders.user_id IS NOT NULL;  -- 优化器可能自动转成 INNER JOIN

4. 聚合和分组优化

  1. Loose Index Scan(松散索引扫描)

    • 优化 GROUP BY,避免全表扫描:

      sql 复制代码
      SELECT category, COUNT(*) FROM products GROUP BY category;
      -- 如果 (category) 有索引,可能直接扫描索引而非全表
  2. Using Temporary + Filesort → 直接索引排序

    • MySQL 会尝试避免临时表排序,尽量使用索引。
    sql 复制代码
    SELECT * FROM users WHERE age > 20 ORDER BY name;
    -- 如果 (age, name) 有索引,优化器会避免 Filesort

5. 数据访问优化

  1. Buffer Pool 缓存

    • 如果数据已经被缓存,优化器会 避免磁盘 I/O
  2. 并行查询(MySQL 8.0+)

    • 某些查询可能 并行执行 (如 COUNT(*))。
  3. Optimizer Hints 优化器提示

    • 可手动指定索引、JOIN 顺序:

      sql 复制代码
      SELECT /*+ INDEX(users idx_age) */ * FROM users WHERE age = 20;

6. 查询执行优化

  1. 延迟 JOIN(Delayed Join)

    • 先过滤数据再 JOIN,减少中间结果集。
  2. LIMIT 优化

    sql 复制代码
    SELECT * FROM users LIMIT 10;
    -- MySQL 检测到 LIMIT 时,可能在索引扫描时直接返回 10 条
  3. 统计信息更新

    • 优化器基于 ANALYZE TABLE 的统计信息决定执行计划。

总结

优化技术 说明
谓词下推(Predicate Pushdown) 尽早用 WHERE 减少数据量
覆盖索引(Covering Index) 直接从索引读取数据,避免回表
ICP(索引条件推送) 存储引擎层过滤数据
MRR / BKA 优化 JOIN 的随机 I/O
Hash Join 大表 JOIN 优化(MySQL 8.0+)
Loose Index Scan 快速 GROUP BY
子查询物化(Subquery Materialization) 避免重复计算 IN 子查询
延迟 JOIN 先过滤再连接

⚠️ 验证执行计划

EXPLAIN + EXPLAIN ANALYZE(MySQL 8.0+)查看查询如何优化!

如果有具体查询优化问题,可以提供 SQL,我可以帮你分析执行计划! 🚀

相关推荐
杨浦老苏5 小时前
基于MongoDB Atlas的博客热榜
数据库·博客·blog·waline
Bert.Cai5 小时前
MySQL RAND()函数详解
数据库·mysql
怪我冷i5 小时前
多租户系统PostgreSQL
数据库·postgresql
发现你走远了5 小时前
极简后端环境搭建:一行 Docker 命令部署四大核心数据库(避坑 PG 18+)
数据库·docker·容器
北重楼015 小时前
如何取消一个挂起的 PostgreSQL 查询
数据库·postgresql
与数据交流的路上5 小时前
mysql参数-优化器 range_optimizer_max_mem_size 相关
数据库·mysql
PaperData5 小时前
2012-2022年农业产业结构高级化
数据库·人工智能·数据分析·经管
喝可乐的希饭a5 小时前
MYSQL的mvcc
数据库·mysql
冷小鱼6 小时前
Valkey 深度剖析:Redis 最佳平替的技术全景
数据库·redis·缓存·valkey