• 从join的实现窥探MySQL迭代器


    以如下left join查询语句为范例:

    select * from t1 left join t2 on t1.c=t2.a ;

      以下初始化数据:

      1  DROP TABLE IF EXISTS `t1`;
      2    CREATE TABLE `t1` (
      3      `a` int DEFAULT NULL,
      4      `b` varchar(20) DEFAULT NULL
      5    )
      6    INSERT INTO `t1` VALUES (1, 'a');
      7    INSERT INTO `t1` VALUES (1, 'b');
      8    INSERT INTO `t1` VALUES (4, 'a');
      9    INSERT INTO `t1` VALUES (5, 'a');
      10    
      11    DROP TABLE IF EXISTS `t2`;
      12    CREATE TABLE `t2` (
      13      `c` int DEFAULT NULL,
      14      `d` varchar(20) DEFAULT NULL
      15    )
      16    INSERT INTO `t2` VALUES (9, 'i');
      17    INSERT INTO `t2` VALUES (1, 'i');
      18    INSERT INTO `t2` VALUES (2, 'i');
      19    INSERT INTO `t2` VALUES (3, 'i');
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18

      1.处理join的yacc入口

      sys_yacc.yy文件内解析t1 left join t2 on t1.c=t2.a;对应处理位置

      1  table_reference outer_join_type table_reference ON_SYM expr
      2    {
      3  $$= NEW_PTN PT_joined_table_on($1, @2, $2, $3, $5);
      4    }
      • 1
      • 2
      • 3

      其中outer_join_type对应

      1  outer_join_type:
      2    LEFT opt_outer JOIN_SYM          { $$= JTT_LEFT; }
      3  | RIGHT opt_outer JOIN_SYM         { $$= JTT_RIGHT; }
      • 1
      • 2

      入参处理在函数T_joined_table_on

      2.移步到函数PT_joined_table_on

      PT_joined_table_on声明可知其继承PT_joined_table函数,入参左右表赋值为PT_joined_table内定义的tr1tr2

      函数PT_joined_table_on将输入join的左右表加入context内,并调用add_join_on将on内的条件加入右表,记录后续数据过滤条件。

      3.执行阶段函数do_command(thd)

      具体对应执行函数int mysql_execute_command(THD *thd, bool first_level),语句解析以及相应参数保存完成后,进入函数int mysql_execute_command(THD *thd, bool first_level),此函数内根据前面解析到的命令类型switch (lex->sql_command)调用对应的处理函数,如当前语句为例查询命令解析为lex->sql_command = SQLCOM_SELECT则进入函数lex->m_sql_cmd->execute(thd);其对应为sql_select.cc内函数bool Sql_cmd_dml::execute(THD *thd)

      4.优化器操作,生成access_paths

      sql_select.cc内函数bool Sql_cmd_dml::execute(THD *thd)函数内主要操作为函数execute_inner,在函数execute_inner内首先会对当前的执行优化操作,

      1. 调用查询表达式Query_expression的优化器unit->optimize,此函数中会对该Query_expression的内的每个查询块query_block分别先进行优化操作,
      2. 查询块内函数bool JOIN::optimize()内会将每个查询块优化生成查询执行计划 ,具体执行函数为函数JOIN::create_access_paths()create_root_access_path_for_join()函数,以当前查询为例在函数create_root_access_path_for_join内根据参数条件主要调用ConnectJoins函数
      3. 在函数ConnectJoins内调用FindSubstructure判断是join类型内连接、外连接、半链接等类型
      4. 根据FindSubstructure返回join类型调用相应的函数生成path,当前查询为例执行调用CreateHashJoinAccessPath生成path。

      至此查询块query_block的优化操作和path生成完成,查询块优化操作完成后再执行整体表达式Query_expression的优化和path的生成,因为目前范例仅为一个查询块,所以当前无需再做整体表达式的优化和path生成。

      5.创建迭代器iterator

      根据上一步生成的path调用CreateIteratorFromAccessPath函数生成迭代器,用于循环操作各表数据。

      在此函数内会根据path的类型调用生成不同类型的迭代器,以目前范例为例,会调用迭代器类型为HashJoinIterator

      6.上述4、5步执行完成后,执行迭代器iterator

      在函数execute_inner内执行完成上述4、5步骤操作后主要继续执行unit->execute(thd)函数,其对应执行查询表达式函数bool Query_expression::ExecuteIteratorQuery(THD *thd)

      1. 函数Query_expression::ExecuteIteratorQuery内主要执行m_root_iterator->Init(),迭代器iterator初始化,当前范例为使用HashJoinIterator类型迭代器,因此对应执行迭代器函数HashJoinIterator::Init()
      2. 执行m_build_input->Init()来初始右表table句柄,用于下面函数BuildHashTable()内读取右表数据以便初始化返回数据存储表hashtable,值得注意的是BuildHashTable函数内会根据处理流程调用SetReadingProbeRowState设置执行状态用于引导后续迭代器iterator执行流程。
      3. 函数内最后调用InitProbeIterator执行m_probe_input->Init()初始左表table句柄用于下面函数读取左表数据。
      4. 上面操作完成后执行m_root_iterator->Read()函数,以当前查询为范例其对应int HashJoinIterator::Read()函数,执行过程中根据前面SetReadingProbeRowState设置的流程状态再选择对应的操作函数,以当前范例则会循环读取左表数据,而在操作函数内也会调用SetReadingProbeRowState来设置迭代器iterator下一步操作,直至迭代器处理完成,其中在函数Query_expression::ExecuteIteratorQuery,每次读取一条成功后就会调用send_data操作将结果发送至客户端,直至所有查询结果发送完成。

      7.至此客户端收到相应显示查询结果。


      Enjoy GreatSQL :)

      关于 GreatSQL

      GreatSQL是由万里数据库维护的MySQL分支,专注于提升MGR可靠性及性能,支持InnoDB并行查询特性,是适用于金融级应用的MySQL分支版本。

      相关链接: GreatSQL社区 Gitee GitHub Bilibili

      GreatSQL社区:

      欢迎来GreatSQL社区发帖提问 https://greatsql.cn/

      GreatSQL社区

      技术交流群:

      微信:扫码添加GreatSQL社区助手微信好友,发送验证信息加群

      图片

    • 相关阅读:
      Cyclopropene-PEG-leucine|环丙烯-聚乙二醇-亮氨酸|环丙烯PEG修饰亮氨酸
      Spring中ApplicationListener事件监听机制详解
      Java框架 Spring5--JdbcTemplate
      升级cordova-ios 6以上版本 Xcode打开xcodeproj文件
      数据源、映射器的复用
      vue-router源码分析(下)
      [游戏设计心法]4-如何让玩家投入
      8-Spring架构源码分析-IoC 之解析Bean:解析 import 标签
      从零开始学习typescript——数据类型
      蓝桥等考C++组别一级009
    • 原文地址:https://blog.csdn.net/GreatSQL2021/article/details/126871971