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,我可以帮你分析执行计划! 🚀

相关推荐
SelectDB8 分钟前
抖音集团 实时数据仓库:Apache Doris / SelectDB 的技术能力与实践
数据库
SelectDB16 分钟前
网易 日志与时序数据分析:Apache Doris / SelectDB 的技术能力与实践
数据库
weixin_539446781 小时前
Navicat Premium 17报缺少ODBC驱动
数据库
这个DBA有点耶1 小时前
迁移中的数据一致性挑战:如何确保百万行数据“搬得对”
mysql·架构·dba
哦虎!1 小时前
【数据库】事务
java·数据库·mysql
倔强的石头_1 小时前
时序数据库的难题不只在写入速度
数据库
IT古董3 小时前
【WMS学习笔记系列】01-需求分析
大数据·数据库
zlinear数据采集卡3 小时前
数据采集卡从入门到精通(9):分辨率与精度——16位卡不等于1/65536的精度
开发语言·数据库·fpga开发·开源·c#
Mico184 小时前
麒麟v10-MySQL InnoDB Cluster 完整部署与全场景验证(从入门到精通)
数据库·mysql