MySQL优化器追踪(Optimizer Trace)的使用小结

 更新时间:2025年08月24日 09:53:09   作者:索java  
MySQL OptimizerTrace 是用于分析查询优化器决策过程的工具,通过输出JSON格式的详细执行信息,帮助开发者理解优化器如何选择执行计划,感兴趣的可以了解一下

1.1 Optimizer Trace简介

1.1 引入背景

在MySQL中,查询优化器负责解析SQL语句,并根据成本估算选择最优执行计划。然而,对于复杂查询,有时优化器的决策过程难以理解,尤其是出现:

  • 索引选择错误
  • 连接顺序不合理
  • 成本估算偏差

为了解决这些问题,MySQL从5.6版本引入了 Optimizer Trace 功能,用于追踪优化器的内部决策过程,以 JSON 格式输出详细执行信息。

官方文档链接
MySQL 8.0 Reference Manual - Optimizer Trace

1.2 Optimizer Trace 与 EXPLAIN 的区别

特性EXPLAINOptimizer Trace
输出内容查询执行计划优化器内部决策详细信息(JSON)
适用场景查看执行顺序、索引使用情况分析优化器为何选择特定执行计划
输出格式表格JSON
层级信息平面层次化(join_preparation、join_optimization等)
调试价值较低高,可定位优化器决策逻辑问题

可以把 EXPLAIN 理解为“最终计划的快照”,而 Optimizer Trace 则是“优化器的思考过程记录”。

1.3 适用场景

  • 复杂多表 JOIN 查询调试:理解优化器如何选择连接顺序
  • 索引选择异常:查看优化器为何未使用期望索引
  • 成本估算异常:分析行数估算、过滤率计算
  • 调优验证:确认优化器是否采纳了调优建议

1.4 示例代码:开启 Optimizer Trace 并执行简单查询

环境:MySQL 8.0,单机测试

-- 开启 Optimizer Trace
SET optimizer_trace="enabled=on";
 
-- 创建测试表
CREATE TABLE employees (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    department_id INT,
    INDEX idx_dept(department_id)
);
 
INSERT INTO employees VALUES
(1,'Alice',1),
(2,'Bob',2),
(3,'Charlie',1);
 
-- 执行简单查询
SELECT * FROM employees WHERE department_id = 1;
 
-- 查看 Optimizer Trace
SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE\G
 
-- 关闭 Optimizer Trace
SET optimizer_trace="enabled=off";

预期结果

  • INFORMATION_SCHEMA.OPTIMIZER_TRACE 返回 JSON 结构
  • JSON 包含 stepsjoin_ordercosts 等字段
  • 可以看到优化器如何决定使用 idx_dept 索引

2 工作原理与核心价值

2.1 Optimizer Trace 的工作阶段

Optimizer Trace 会在查询优化阶段对优化器的决策流程进行追踪,主要包括以下几个阶段(Stage):

join_preparation

功能:初始化 JOIN 查询的基本信息

内容:

  • 表数量、别名信息
  • 每个表的访问方式(全表扫描、索引访问)
  • 相关统计信息(行数、索引基数)

作用:为后续优化器选择最优 JOIN 顺序做准备

join_optimization

功能:选择最优连接顺序和访问方法

内容:

  • 每个 JOIN 的可能访问方式(access path)
  • 成本估算(cost estimation)
  • 排序选择(order of tables)

作用:记录优化器如何计算每种执行方案的代价并选择最优方案

final_plan

功能:生成最终执行计划

内容:

  • 确定访问索引
  • 确定连接类型(Nested Loop、Block Nested Loop、Hash Join 等)
  • 预估扫描行数和代价

作用:把优化器的“思考结果”形成可执行计划

注意:每个阶段都会输出 JSON 结构,包含详细的决策信息,包括成本(cost)、扫描行数(rows)、使用索引(access_method)等。

2.2 JSON 输出结构解析

Optimizer Trace 输出主要字段说明:

{
  "trace": [
    {
      "step": 1,
      "phase": "join_preparation",
      "table": "employees",
      "access_method": "ALL",
      "rows": 3
    },
    {
      "step": 2,
      "phase": "join_optimization",
      "join_order": ["employees"],
      "cost": 0.03,
      "chosen_access": "index(idx_dept)"
    },
    {
      "step": 3,
      "phase": "final_plan",
      "plan": [
        {
          "table": "employees",
          "access_method": "index",
          "key": "idx_dept",
          "rows_examined": 2
        }
      ]
    }
  ]
}

字段说明

字段说明
step优化器执行步骤序号
phase优化阶段(join_preparation、join_optimization、final_plan)
table当前操作的表
access_method表访问方式(ALL 表示全表扫描,index 表示索引访问)
rows预估扫描行数
join_order优化器尝试的表连接顺序
cost优化器对执行方案的代价估算
chosen_access优化器最终选择的访问方式
plan最终执行计划详细信息
key使用的索引
rows_examined实际预计扫描行数

通过这个 JSON 输出,开发者可以 逐步追踪优化器的每个决策,并分析为什么某些索引未被使用、JOIN 顺序为何不合理。

2.3 Optimizer Trace 的核心价值

可视化优化器决策过程

对比 EXPLAIN,Trace 不仅展示最终计划,还展示选择路径和成本比较。

定位索引选择问题

能够分析为什么优化器没有选择期望索引,便于调整统计信息或优化 SQL。

分析成本估算偏差

Trace 提供每一步的成本和行数估算,方便对比实际执行情况。

调优验证

调整索引或 SQL 后,可通过 Trace 验证优化器是否采纳建议。

结合 EXPLAIN 使用

EXPLAIN 展示最终计划,Trace 展示优化器思路,二者结合可以完整理解查询执行逻辑。

2.4 示例代码:分析复杂查询的 Trace 输出

环境:MySQL 8.0

-- 开启 Trace
SET optimizer_trace='enabled=on';
 
-- 创建测试表
CREATE TABLE departments (
    id INT PRIMARY KEY,
    name VARCHAR(50)
);
 
CREATE TABLE employees (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    department_id INT,
    INDEX idx_dept(department_id)
);
 
INSERT INTO departments VALUES (1,'HR'),(2,'IT');
INSERT INTO employees VALUES (1,'Alice',1),(2,'Bob',2),(3,'Charlie',1);
 
-- 执行多表 JOIN 查询
SELECT e.name, d.name
FROM employees e
JOIN departments d ON e.department_id = d.id
WHERE d.id = 1;
 
-- 查看 Trace
SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE\G
 
-- 关闭 Trace
SET optimizer_trace='off';

分析步骤

  • 查看 join_preparation 阶段,确认优化器识别了两个表及索引信息。
  • join_optimization 阶段,分析优化器尝试的连接顺序和代价比较。
  • final_plan 阶段,确认最终选择了 idx_dept 索引访问 employees 表,并输出预估扫描行数。
  • 对比 EXPLAIN 输出,验证 Trace 的决策与最终执行计划一致性。

3 配置参数详解

Optimizer Trace 依赖 MySQL 系统变量来控制开启、输出内容和调试精度。主要参数包括:

3.1 optimizer_trace

作用:控制 Optimizer Trace 功能开关

类型:字符串(枚举 enabled=on|off 或 JSON 配置)

默认值enabled=off

修改方法

-- 开启 Trace
SET optimizer_trace='enabled=on';
 
-- 关闭 Trace
SET optimizer_trace='enabled=off';

JSON 形式

SET optimizer_trace='{
    "enabled": true,
    "trace_objects": "all",
    "max_elements": 1000
}';

trace_objects:指定追踪对象,可选 alloptimizer

max_elements:JSON 输出中最大元素数,超过会被截断

3.2 optimizer_trace_features

作用:控制 Trace 输出的内容粒度

类型:字符串(逗号分隔)

默认值"basic"

可选值

  • basic:基本信息(表、访问方法、成本)
  • io:包含 I/O 成本
  • memory:包含内存使用估算
  • all:包含全部详细信息

修改方法

SET optimizer_trace_features='all'; 

3.3 max_optimizer_trace_elements

作用:限制 Trace 输出的最大元素数量

类型:整数

默认值1000

修改方法

SET max_optimizer_trace_elements=2000; 

影响:如果 Trace 输出超过限制,JSON 会被截断,分析不完整。

3.4 注意事项

系统级变量 vs 会话级变量

  • SET GLOBAL optimizer_trace='...':修改全局,重启后生效
  • SET SESSION optimizer_trace='...':只对当前会话有效

与其他参数的冲突

  • 开启 optimizer_trace 时,如果 max_optimizer_trace_elements 太小,复杂查询的 Trace 会被截断
  • 输出 JSON 大量元素可能导致查询慢,因此只在调试环境开启

对性能的影响

  • 开启 Trace 会增加优化器计算开销
  • 生产环境应谨慎开启,仅用于分析问题

3.5 示例:调整参数并观察 Trace 输出差异

环境:MySQL 8.0,测试库

-- 创建测试表
CREATE TABLE test_employees (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    dept_id INT,
    INDEX idx_dept(dept_id)
);
 
INSERT INTO test_employees VALUES (1,'Alice',1),(2,'Bob',2),(3,'Charlie',1);
 
-- 开启 Trace 并设置输出全部详细信息
SET optimizer_trace='enabled=on';
SET optimizer_trace_features='all';
SET max_optimizer_trace_elements=5000;
 
-- 执行查询
SELECT * FROM test_employees WHERE dept_id=1;
 
-- 查看 Trace
SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE\G
 
-- 调整参数只输出 basic
SET optimizer_trace_features='basic';
 
-- 再次执行查询查看差异
SELECT * FROM test_employees WHERE dept_id=1;
 
-- 关闭 Trace
SET optimizer_trace='enabled=off';

预期效果

  • optimizer_trace_features='all':输出包含 I/O、内存估算等完整信息
  • optimizer_trace_features='basic':只输出表、访问方法、行数和成本
  • 通过对比,可以清晰看到不同参数对 Trace 输出内容的影响

3.6 小结

  • optimizer_trace:开启/关闭 Trace
  • optimizer_trace_features:控制输出粒度
  • max_optimizer_trace_elements:控制最大输出元素数
  • 调整参数可以帮助在不同调试场景下获取所需信息,同时避免不必要的性能开销

4 使用方法与调试流程

Optimizer Trace 的使用主要包括四个步骤:开启 Trace → 执行查询 → 查看 Trace → 分析与验证。下面逐步讲解。

4.1 步骤 1:开启 Optimizer Trace

基本开启方法(会话级):

SET optimizer_trace='enabled=on';

指定输出详细程度(可选):

SET optimizer_trace_features='all';  -- 输出所有信息,包括 I/O 和内存估算
SET max_optimizer_trace_elements=5000;  -- 避免复杂查询输出被截断

关闭 Trace

SET optimizer_trace='enabled=off';

注意:生产环境中建议仅在调试场景开启,以避免性能开销。

4.2 步骤 2:执行需要分析的查询

示例:MySQL 8.0

CREATE TABLE employees (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    department_id INT,
    INDEX idx_dept(department_id)
);
 
CREATE TABLE departments (
    id INT PRIMARY KEY,
    name VARCHAR(50)
);
 
INSERT INTO departments VALUES (1,'HR'),(2,'IT');
INSERT INTO employees VALUES (1,'Alice',1),(2,'Bob',2),(3,'Charlie',1);
 
-- 执行复杂 JOIN 查询
SELECT e.name, d.name
FROM employees e
JOIN departments d ON e.department_id = d.id
WHERE d.id = 1;
  • 查询执行过程中,优化器会根据统计信息计算多个执行方案,并记录在 Trace 中
  • Trace 会捕捉每个阶段(join_preparation、join_optimization、final_plan)的决策

4.3 步骤 3:查看 Trace 输出

查询 Trace:

SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE\G; 

输出分析:

  • trace 字段为 JSON,包含所有优化器决策步骤

关键字段:

  • phase:优化阶段
  • table:操作的表
  • access_method:表访问方式
  • rows:预估扫描行数
  • cost:优化器成本估算
  • chosen_access:最终选择访问方式
  • plan:最终执行计划详情

结合 JSON 格式化工具,可清晰看到优化器每一步决策过程。

4.4 步骤 4:分析与验证

与 EXPLAIN 对比

EXPLAIN SELECT e.name, d.name
FROM employees e
JOIN departments d ON e.department_id = d.id
WHERE d.id = 1\G;
  • EXPLAIN 提供最终执行计划,包含访问索引、连接类型、扫描行数
  • Optimizer Trace 提供优化器选择该计划的完整逻辑

分析决策过程

查看 join_optimization 阶段:

  • 哪些访问方案被尝试
  • 各方案成本估算
  • 为什么最终选择当前方案

查看 final_plan 阶段:

  • 验证访问索引是否符合预期
  • 验证扫描行数与成本是否合理

调试索引选择错误示例

假设优化器未使用期望索引:

-- 查询未使用索引
SELECT * FROM employees WHERE department_id=1;
 
-- Trace 显示 access_method=ALL(全表扫描)
-- 分析可能原因:
-- 1. 索引统计信息不准确
-- 2. 表行数过少,优化器认为全表扫描成本低
-- 调整统计信息
ANALYZE TABLE employees;
 
-- 再次执行查询,观察 Trace 输出是否选择 idx_dept 索引

通过对比 Trace 输出,可以清楚看到优化器为何选择或忽略某个索引,从而指导索引优化或 SQL 调整。

4.5 小结

  • 开启 Trace → 执行查询 → 查看输出 → 分析决策 是标准流程
  • Trace 能够详细记录优化器每个阶段的决策,包括访问方式、成本估算、连接顺序
  • 与 EXPLAIN 配合使用,可以同时掌握最终计划与优化器思路
  • 适用于调试复杂查询、索引选择错误、成本估算偏差等问题

5 典型场景分析

场景1:索引选择错误

5.1.1 问题描述

  • 查询条件明确,但优化器未使用预期索引
  • 导致全表扫描或性能下降

示例查询(MySQL 8.0):

SELECT * FROM employees WHERE department_id = 1; 

5.1.2 Trace 输出分析

{
  "trace": [
    {
      "phase": "join_preparation",
      "table": "employees",
      "access_method": "ALL",
      "rows": 3
    },
    {
      "phase": "final_plan",
      "plan": [
        {
          "table": "employees",
          "access_method": "ALL",
          "rows_examined": 3
        }
      ]
    }
  ]
}

分析:

access_method=ALL 表示全表扫描

优化器认为全表扫描成本低于索引访问,可能由于:

  • 表数据量小
  • 索引统计信息过时

5.1.3 调优建议

-- 更新表统计信息
ANALYZE TABLE employees;
 
-- 再次执行查询,观察 Trace 输出
SELECT * FROM employees WHERE department_id=1;
 
-- 预期 Trace 输出:
-- access_method=index
-- 使用 idx_dept 索引

场景2:成本估算偏差

5.2.1 问题描述

  • 优化器选择的执行计划成本估算与实际执行成本差距大
  • 可能导致非最优查询计划

示例:

SELECT * FROM employees e
JOIN departments d ON e.department_id = d.id
WHERE d.id IN (1,2);

5.2.2 Trace 输出分析

{
  "phase": "join_optimization",
  "join_order": ["departments","employees"],
  "cost": 0.05,
  "chosen_access": "index(idx_dept)"
}

分析:

  • 优化器选择先扫描 departments 再扫描 employees
  • 如果统计信息不准确,实际扫描行数可能比估算大
  • Trace 提供每个阶段成本和行数估算,有助于定位问题

5.2.3 调优建议

-- 更新表统计信息
ANALYZE TABLE employees;
ANALYZE TABLE departments;
 
-- 调整查询逻辑或提示优化器
SELECT /*+ JOIN_ORDER(d,e) */ e.name, d.name
FROM employees e
JOIN departments d ON e.department_id = d.id
WHERE d.id IN (1,2);

场景3:子查询优化问题

5.3.1 问题描述

  • 子查询导致性能不佳,优化器未转换为 JOIN
  • Trace 可以帮助分析子查询执行计划

示例:

SELECT name
FROM employees
WHERE department_id IN (
    SELECT id FROM departments WHERE name='HR'
);

5.3.2 Trace 输出分析

{
  "phase": "join_optimization",
  "subquery": {
    "type": "IN",
    "rows": 1,
    "access_method": "ALL"
  },
  "final_plan": {
    "employees": {"access_method": "index", "rows_examined": 2}
  }
}

分析:

  • 子查询使用全表扫描,可能导致性能下降
  • Trace 显示优化器未将子查询转换为半连接(semi-join)

5.3.3 调优建议

-- 转换为 JOIN
SELECT e.name
FROM employees e
JOIN departments d ON e.department_id = d.id
WHERE d.name='HR';

Trace 输出应显示:

  • access_method=index
  • 子查询被消除,性能提升明显

场景4:临时表/文件排序问题

5.4.1 问题描述

  • 查询涉及 ORDER BY、GROUP BY 或 DISTINCT
  • 优化器使用临时表或文件排序,影响性能

示例:

SELECT department_id, COUNT(*) 
FROM employees
GROUP BY department_id
ORDER BY COUNT(*) DESC;

5.4.2 Trace 输出分析

{
  "phase": "final_plan",
  "plan": [
    {
      "table": "employees",
      "access_method": "index",
      "using_temporary": true,
      "using_filesort": true
    }
  ]
}

分析:

  • using_temporary=trueusing_filesort=true 表示临时表 + 文件排序
  • 对大表可能导致性能瓶颈

5.4.3 调优建议

-- 使用覆盖索引或调整查询
CREATE INDEX idx_dept_count ON employees(department_id);
 
-- 执行查询并观察 Trace 输出
-- 预期不再使用文件排序,性能提升

5.5 小结

Optimizer Trace 能清晰展示优化器每一步决策

通过 Trace 可定位:

  • 索引未使用
  • 成本估算不准
  • 子查询优化未生效
  • 临时表或文件排序影响性能

调优流程:

  • 查看 Trace
  • 分析决策逻辑
  • 调整索引或 SQL
  • 验证 Trace 输出变化

到此这篇关于MySQL优化器追踪(Optimizer Trace)的使用小结的文章就介绍到这了,更多相关MySQL优化器追踪内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

相关文章

  • MySQL慢查询查找和调优测试

    MySQL慢查询查找和调优测试

    MySQL慢查询查找和调优测试,接下来详细介绍,需要了解的朋友可以参考下
    2013-01-01
  • mysql快速获得库中无主键的表实例代码

    mysql快速获得库中无主键的表实例代码

    这篇文章主要给大家介绍了关于mysql如何快速获得库中无主键的表的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者使用mysql具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-10-10
  • MySQL 用户创建与授权最佳实践

    MySQL 用户创建与授权最佳实践

    在MySQL中,用户管理和权限控制是数据库安全的重要组成部分,下面详细介绍如何在MySQL中创建用户并授予适当的权限,感兴趣的朋友跟随小编一起看看吧
    2025-06-06
  • 有关SQL模糊查询

    有关SQL模糊查询

    在进行数据库查询时,有完整查询和模糊查询之分,这里简单介绍下,方便需要的朋友
    2006-12-12
  • Windows下MySQL安装教程图文详解

    Windows下MySQL安装教程图文详解

    本文通过图文并茂的形式给大家介绍了windows下mysql 安装教程,非常不错,具有一定的参考借鉴价值,需要的朋友参考下吧
    2018-10-10
  • MySQL实现字段或字符串拼接的三种方式总结

    MySQL实现字段或字符串拼接的三种方式总结

    这篇文章主要为大家详细介绍了MySQL中实现字段或字符串拼接的三种方式,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-01-01
  • mysql提示Changed limits: max_open_files: 2048 max_connections: 1910 table_cache: 64的解决

    mysql提示Changed limits: max_open_files: 2048 max_connections:

    这篇文章主要介绍了mysql提示Changed limits: max_open_files: 2048 max_connections: 1910 table_cache: 64的解决,需要的朋友可以参考下
    2014-05-05
  • MySQL中的存储过程异常处理

    MySQL中的存储过程异常处理

    这篇文章主要介绍了MySQL中的存储过程异常处理方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • 分享20个数据库设计的最佳实践

    分享20个数据库设计的最佳实践

    下面给出了20个数据库设计最佳实践,当然,所谓最佳,还是要看它是否适合你的程序。一起来了解了解吧
    2014-06-06
  • Mysql更新自增主键id遇到的问题

    Mysql更新自增主键id遇到的问题

    本文主要介绍了Mysql更新自增主键id遇到的问题,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下<BR>
    2021-11-11

最新评论