MySQL 8 C++ 源码解析:EXPLAIN 实现机制

在 MySQL 中,EXPLAIN 是分析查询执行计划的核心工具。其源码实现涉及 查询解析优化器决策 和 执行计划生成 等多个模块。本文基于 MySQL 8.1.0 源码,深入解析 EXPLAIN 的实现逻辑。


1. 整体架构与入口

(1) 命令分发:mysql_execute_command

所有 SQL 命令的入口函数为 mysql_execute_command(位于 sql/sql_parse.cc)。EXPLAIN 作为 DML 的扩展命令,通过 lex->sql_command 标识类型:

 
switch (lex->sql_command) {
  case SQLCOM_EXPLAIN:      // 标准 EXPLAIN SELECT/UPDATE/DELETE
  case SQLCOM_EXPLAIN_OTHER:// EXPLAIN FOR CONNECTION 或特殊格式
    // 调用 DML 执行逻辑
    res = lex->m_sql_cmd->execute(thd);
    break;
  // 其他命令分支...
}
  • 关键逻辑EXPLAIN 被归类为 SQLCOM_EXPLAIN 或 SQLCOM_EXPLAIN_OTHER,触发 DML 执行路径。

2. DML 执行入口:Sql_cmd_dml::execute_inner

(1) 优化与执行计划生成

EXPLAIN 的核心逻辑在 Sql_cmd_dml::execute_inner(位于 sql/sql_select.cc):

 
bool Sql_cmd_dml::execute_inner(THD *thd) {
  Query_expression *unit = lex->unit;
  
  // 1. 优化查询表达式(生成 AccessPath)
  if (unit->optimize(thd, /*materialize_destination=*/nullptr,
                     /*create_iterators=*/true, /*finalize_access_paths=*/true))
    return true;

  // 2. 处理 EXPLAIN 逻辑
  if (lex->is_explain()) {
    if (explain_query(thd, thd, unit)) return true;
  }
  return false;
}
  • 核心步骤
    1. unit->optimize:调用优化器生成执行计划(AccessPath 结构)。
    2. explain_query:根据优化结果生成可读的执行计划输出。

3. 执行计划生成:explain_query 函数

(1) 输出格式处理

explain_query(位于 sql/opt_explain.cc)负责将优化器生成的 AccessPath 转换为文本、JSON 或树形格式:

 
bool explain_query(THD *explain_thd, const THD *query_thd, Query_expression *unit) {
  // 1. 判断是否使用迭代器模式(如 JSON/TREE 格式)
  if (lex->explain_format->is_iterator_based()) {
    return ExplainIterator(explain_thd, query_thd, unit);
  }

  // 2. 传统格式(TRADITIONAL)
  return mysql_explain_query_expression(explain_thd, query_thd, unit);
}
  • 分支逻辑
    • 迭代器模式:用于 FORMAT=JSON 或 FORMAT=TREE,调用 ExplainIterator
    • 传统模式:生成表格形式的输出,调用 mysql_explain_query_expression

4. 优化器交互:Query_expression::optimize

(1) 优化流程

Query_expression::optimize(位于 sql/sql_union.cc)负责对查询表达式(如 UNION)进行优化:

 
bool Query_expression::optimize(THD *thd, ...) {
  // 1. 优化每个查询块(Query_block)
  for (Query_block *query_block = first_query_block(); query_block; query_block = query_block->next_query_block()) {
    query_block->optimize(thd, finalize_access_paths);
  }

  // 2. 处理集合操作(UNION/INTERSECT)
  if (!is_simple()) optimize_set_operand(thd, this, query_term());

  // 3. 生成访问路径(AccessPath)
  create_access_paths(thd);
}
  • 核心操作
    1. 单查询块优化:为每个 SELECT 子句生成最优执行路径。
    2. 集合操作处理:优化 UNION 等操作的排序、去重逻辑。
    3. 访问路径生成:将优化结果封装为 AccessPath 结构,供执行引擎使用。

5. 特殊场景处理

(1) EXPLAIN ANALYZE

当启用 EXPLAIN ANALYZE 时,源码会 实际执行查询 并收集性能数据:

 
if (lex->is_explain_analyze) {
  Query_result_null null_result;
  unit->set_query_result(&null_result);  // 抑制结果输出
  unit->execute(thd);                    // 实际执行查询
  ExplainIterator(explain_thd, query_thd, unit); // 生成带统计信息的计划
}
  • 关键逻辑:通过执行查询获取精确的行数、耗时等指标。
(2) 二级引擎支持

若查询使用二级引擎(如 HeatWave),生成警告并调整执行计划:

 
if (SecondaryEngineHandlerton(query_thd) != nullptr) {
  push_warning(explain_thd, "Query may use secondary engine");
  return Explain_secondary_engine(...);  // 生成引擎特定的计划
}

6. 执行计划输出示例

(1) 传统格式(TRADITIONAL)

通过 mysql_explain_query_expression 生成表格:

 
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra          |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
| 1  | SIMPLE      | t     | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1000 | 10.00    | Using where    |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
(2) JSON 格式

通过 ExplainIterator 生成结构化 JSON:

 
{
  "query_block": {
    "select_id": 1,
    "cost_info": {"query_cost": "1.20"},
    "table": {
      "table_name": "t",
      "access_type": "ALL",
      "rows_examined_per_scan": 1000
    }
  }
}

7. 调试与扩展

(1) 调试技巧
  • GDB 断点
     
    break opt_explain.cc:explain_query  # 跟踪 EXPLAIN 入口
    break sql_select.cc:Sql_cmd_dml::execute_inner  # 跟踪优化入口
  • 日志输出
     
    // 在 Query_expression::optimize 中打印优化步骤
    DBUG_PRINT("info", ("Optimizing query block %d", query_block->select_number));
(2) 扩展性
  • 自定义格式:通过继承 Explain_format 类实现新的输出格式。
  • 插件优化器:通过 Optimizer 插件接口扩展优化规则。

总结

MySQL 的 EXPLAIN 实现通过 多层模块协作 完成,从命令解析到优化器决策,最终生成用户可读的执行计划。其源码设计兼顾灵活性与性能,支持多种输出格式和复杂查询场景。理解这一机制,有助于深入掌握 MySQL 的查询优化逻辑,并为性能调优提供底层支持。

##gdb调试堆栈

(gdb) bt
#0  explain_query (explain_thd=0x7c292c001070, query_thd=0x7c292c001070, unit=0x7c292cd4cf70) at /home/yym/mysql8/mysql-8.1.0/sql/opt_explain.cc:2242
#1  0x000062de06742cd8 in Sql_cmd_dml::execute_inner (this=0x7c292cd0c590, thd=0x7c292c001070) at /home/yym/mysql8/mysql-8.1.0/sql/sql_select.cc:1020
#2  0x000062de06742067 in Sql_cmd_dml::execute (this=0x7c292cd0c590, thd=0x7c292c001070) at /home/yym/mysql8/mysql-8.1.0/sql/sql_select.cc:793
#3  0x000062de066b4841 in mysql_execute_command (thd=0x7c292c001070, first_level=true) at /home/yym/mysql8/mysql-8.1.0/sql/sql_parse.cc:4797
#4  0x000062de066b6cb3 in dispatch_sql_command (thd=0x7c292c001070, parser_state=0x7c2a111fd9f0) at /home/yym/mysql8/mysql-8.1.0/sql/sql_parse.cc:5447
#5  0x000062de066ac0d7 in dispatch_command (thd=0x7c292c001070, com_data=0x7c2a111fe340, command=COM_QUERY) at /home/yym/mysql8/mysql-8.1.0/sql/sql_parse.cc:2112
#6  0x000062de066a9f77 in do_command (thd=0x7c292c001070) at /home/yym/mysql8/mysql-8.1.0/sql/sql_parse.cc:1459
#7  0x000062de06901835 in handle_connection (arg=0x62de159f9b90) at /home/yym/mysql8/mysql-8.1.0/sql/conn_handler/connection_handler_per_thread.cc:303
#8  0x000062de08840bdc in pfs_spawn_thread (arg=0x62de159f8fd0) at /home/yym/mysql8/mysql-8.1.0/storage/perfschema/pfs.cc:3043
#9  0x00007c2a1fc94ac3 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#10 0x00007c2a1fd26850 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
(gdb) b Query_expression::optimize
Breakpoint 2 at 0x62de067fe9ac: file /home/yym/mysql8/mysql-8.1.0/sql/sql_union.cc, line 983.

##普通select 查询gdb堆栈

 

(gdb) bt
#0  Query_expression::execute (this=0x7c291070bad0, thd=0x7c2910000bf0) at /home/yym/mysql8/mysql-8.1.0/sql/sql_union.cc:1808
#1  0x000062de06742cf6 in Sql_cmd_dml::execute_inner (this=0x7c29105f3798, thd=0x7c2910000bf0) at /home/yym/mysql8/mysql-8.1.0/sql/sql_select.cc:1022
#2  0x000062de06742067 in Sql_cmd_dml::execute (this=0x7c29105f3798, thd=0x7c2910000bf0) at /home/yym/mysql8/mysql-8.1.0/sql/sql_select.cc:793
#3  0x000062de066b4841 in mysql_execute_command (thd=0x7c2910000bf0, first_level=true) at /home/yym/mysql8/mysql-8.1.0/sql/sql_parse.cc:4797
#4  0x000062de066b6cb3 in dispatch_sql_command (thd=0x7c2910000bf0, parser_state=0x7c2a0befb9f0) at /home/yym/mysql8/mysql-8.1.0/sql/sql_parse.cc:5447
#5  0x000062de066ac0d7 in dispatch_command (thd=0x7c2910000bf0, com_data=0x7c2a0befc340, command=COM_QUERY) at /home/yym/mysql8/mysql-8.1.0/sql/sql_parse.cc:2112
#6  0x000062de066a9f77 in do_command (thd=0x7c2910000bf0) at /home/yym/mysql8/mysql-8.1.0/sql/sql_parse.cc:1459
#7  0x000062de06901835 in handle_connection (arg=0x62de1335a2f0) at /home/yym/mysql8/mysql-8.1.0/sql/conn_handler/connection_handler_per_thread.cc:303
#8  0x000062de08840bdc in pfs_spawn_thread (arg=0x62de158573a0) at /home/yym/mysql8/mysql-8.1.0/storage/perfschema/pfs.cc:3043
#9  0x00007c2a1fc94ac3 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#10 0x00007c2a1fd26850 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
(gdb) p thd->query().str
$16 = 0x7c291070b9f0 "SELECT COUNT(*) FROM yym WHERE DATE_SUB(CURDATE(), INTERVAL 1 DAY)<=create_time\n LIMIT 0, 1000"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/981402.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IndexError: index 0 is out of bounds for axis 1 with size 0

IndexError: index 0 is out of bounds for axis 1 with size 0 欢迎来到英杰社区&#xff0c;这里是博主英杰https://bbs.csdn.net/topics/617804998 报错原因 数组或数据结构为空 如果数组或 DataFrame 在指定的维度上没有任何元素&#xff08;例如&#xff0c;没有列&#x…

本地部署阿里万象2.1文生视频模型(Wan2.1-T2V)完全指南

在生成式AI技术爆发式发展的今天,阿里云开源的万象2.1(Wan2.1)视频生成模型,为创作者提供了从文字/图像到高清视频的一站式解决方案。本文针对消费级显卡用户,以RTX 4060 Ti 16G为例,详解本地部署全流程与性能调优方案,涵盖环境配置、多模型选择策略、显存优化技巧及实战…

[Python学习日记-85] 并发编程之多进程 —— Process 类、join 方法、僵尸进程与孤儿进程

[Python学习日记-85] 并发编程之多进程 —— Process 类、join 方法、僵尸进程与孤儿进程 简介 multiprocessing 模块 Process 类 僵尸进程与孤儿进程 简介 在前面的进程理论的介绍当中我们已经介绍了进程的概念、并发与并行的区别以及进程并发的实现理论&#xff0c;这些都…

飞书考勤Excel导入到自己系统

此篇主要用于记录Excel一行中&#xff0c;单条数据的日期拿取&#xff0c;并判断上下班打卡情况。代码可能满足不了大部分需求&#xff0c;目前只够本公司用&#xff0c;如果需要&#xff0c;可以参考。 需要把飞书月度汇总的考勤表导入系统中可以参考下。 下图为需要获取的年…

Python项目】基于Python的图像去雾算法研究和系统实现

Python项目】基于Python的图像去雾算法研究和系统实现 技术简介&#xff1a;采用Python技术、MYSQL数据库等实现。 系统简介&#xff1a;图像去雾系统主要是基于暗通道先验和逆深度估计技术的去雾算法&#xff0c;系统功能模块分为&#xff08;1&#xff09;图像上传模块&…

游戏引擎学习第135天

仓库:https://gitee.com/mrxiao_com/2d_game_3 回顾 game_asset.cpp 的创建 在开发过程中&#xff0c;不使用任何现成的游戏引擎或第三方库&#xff0c;而是直接基于 Windows 进行开发&#xff0c;因为 Windows 目前仍然是游戏的标准平台&#xff0c;因此首先在这个环境中进行…

【Linux】冯诺依曼体系结构-操作系统

一.冯诺依曼体系结构 我们所使用的计算机&#xff0c;如笔记本等都是按照冯诺依曼来设计的&#xff1a; 截止目前&#xff0c;我们所知道的计算机都是由一个一个的硬件组装起来的&#xff0c;这些硬件又由于功能的不同被分为了输入设备&#xff0c;输出设备&#xff0c;存储器…

[liorf_localization_imuPreintegration-2] process has died

使用liorf&#xff0c;编译没报错&#xff0c;但是roslaunch报错如下&#xff1a; 解决方法&#xff1a; step1: 如果你之前没有安装 GTSAM&#xff0c;可以尝试安装它 step2: 检查是否缺少依赖库 ldd /home/zz/1210/devel/lib/liorf_localization/liorf_localization_imuPr…

模块11_面向对象

文章目录 模块11_面向对象模块十回顾&&模块十一重点 第一章.接口1.接口的介绍2.接口的定义以及使用3.接口中的成员3.1抽象方法3.2默认方法3.3静态方法3.4成员变量3.4成员变量 4.接口的特点5.接口和抽象类的区别 第二章.多态1.多态的介绍2.多态的基本使用3.多态的条件下…

常见webshell工具的流量特征

1、蚁剑 1.1、蚁剑webshell静态特征 蚁剑中php使用assert、eval执行&#xff1b;asp只有eval执行&#xff1b;在jsp使用的是Java类加载&#xff08;ClassLoader&#xff09;&#xff0c;同时会带有base64编码解码等字符特征。 1.2、蚁剑webshell动态特征 查看流量分析会发现…

03标准IO接口

一、系统与标准IO的区别 相同点:系统IO与标准IO都可以操作linux系统下的文件。 ⭐不同点: 系统IO&#xff1a;打开文件得到的是一个整数&#xff0c;称为文件描述符。 标准IO&#xff1a;打开文件得到的是一个指针&#xff0c;称为文件指针。系统IO&#xff1a;可以访问linux…

Axure高保真Element框架元件库

点击下载《Axure高保真Element框架元件库》 原型效果&#xff1a;https://axhub.im/ax9/9da2109b9c68749a/#g1 摘要 本文详细阐述了在 Axure 环境下打造的一套高度还原 Element 框架的组件元件集。通过对 Element 框架组件的深入剖析&#xff0c;结合 Axure 的强大功能&#…

【Linux】进程信号——信号保存和信号捕捉

文章目录 信号保存信号相关的概念信号是如何保存的呢&#xff1f;有关信号保存的系统调用sigprocmask信号的增删查改查看pending表验证接口 信号捕捉用户态与内核态信号捕捉流程 总结 信号保存 信号相关的概念 信号递达&#xff1a;指 操作系统 将一个信号&#xff08;Signal…

【FL0090】基于SSM和微信小程序的球馆预约系统

&#x1f9d1;‍&#x1f4bb;博主介绍&#x1f9d1;‍&#x1f4bb; 全网粉丝10W,CSDN全栈领域优质创作者&#xff0c;博客之星、掘金/知乎/b站/华为云/阿里云等平台优质作者、专注于Java、小程序/APP、python、大数据等技术领域和毕业项目实战&#xff0c;以及程序定制化开发…

因子分析讲解

一、定义 因子分析&#xff08;Factor Analysis&#xff09;是一种常用于多变量统计分析的方法&#xff0c;主要用于数据降维、识别潜在的结构、理解变量间的关系。它通过将一组观察变量&#xff08;通常是高度相关的变量&#xff09;转化为一组较少的、互不相关的因子&#x…

从 JVM 源码(HotSpot)看 synchronized 原理

大家好&#xff0c;我是此林。 不知道大家有没有这样一种感觉&#xff0c;网上对于一些 Java 框架和类的原理实现众说纷纭&#xff0c;看了总是不明白、不透彻。常常会想&#xff1a;真的是这样吗&#xff1f; 今天我们就从 HotSpot 源码级别去看 synchronized 的实现原理。全…

DeepSeek搭配Excel,制作自定义按钮,实现办公自动化!

今天跟大家分享下我们如何将DeepSeek生成的VBA代码&#xff0c;做成按钮&#xff0c;将其永久保存在我们的Excel表格中&#xff0c;下次遇到类似的问题&#xff0c;直接在Excel中点击按钮&#xff0c;就能10秒搞定&#xff0c;操作也非常的简单. 一、代码准备 代码可以直接询问…

Metal学习笔记十一:贴图和材质

在上一章中&#xff0c;您设置了一个简单的 Phong 光照模型。近年来&#xff0c;研究人员在基于物理的渲染 &#xff08;PBR&#xff09; 方面取得了长足的进步。PBR 尝试准确表示真实世界的着色&#xff0c;真实世界中离开表面的光量小于表面接收的光量。在现实世界中&#xf…

zabbix“专家坐诊”第277期问答

在线答疑:乐维社区 问题一 Q&#xff1a;这个怎么解决呢&#xff1f; A&#xff1a;缺少这个依赖。 Q&#xff1a;就一直装不上。 A&#xff1a;装 zabbix-agent2-7.0.0-releasel.el7.x86 64 需要前面提示的那个依赖才可以装。 问题二 Q&#xff1a;大佬&#xff0c;如果agen…

让单链表不再云里雾里

一日不见&#xff0c;如三月兮&#xff01;接下来与我一起创建单链表吧&#xff01; 目录 单链表的结构&#xff1a; 创建单链表&#xff1a; 增加结点&#xff1a; 插入结点&#xff1a; 删除结点&#xff1a; 打印单链表&#xff1a; 单链表查找&#xff1a; 单链表…