MySQL 8.0.22执行器源码分析HashJoin —— 一些初始化函数的细节步骤

目录

    • InitRowBuffer(101行~126行)
    • InitProbeIterator(142行~153行)
    • *HashJoinIterator* 的Init(155行~240行)
    • InitializeChunkFiles(364行~401行)
    • InitWritingToProbeRowSavingFile(1115~1119)
    • InitReadingFromProbeRowSavingFile(1121~1126)

让我们接着上一篇分析BuildHashTable函数细节步骤继续吧,这些函数都在hash_join_iterator.cc文件中。

InitRowBuffer(101行~126行)

需要注意的两个步骤

1、初始化row buffer,使用到一个seed。具体哈希计算算法我并没有特定去了解,这里也就不深入了

kHashTableSeed是个没有意义的数字,是用于计算hash的key。一个种子在内存哈希表中进行哈希运算,一个种子计算用于确定chunk 文件应该放置的行。如果两个操作使用同一个种子,将会把块文件加载到哈希表中,这样是错误的。

2、初始化row buffer后,需要调整迭代器的指向,将其头尾均指向row buffer的尾部。

......
if (m_row_buffer.Init(kHashTableSeed)) {DBUG_ASSERT(thd()->is_error());  // my_error should have been called.return true;
}m_hash_map_iterator = m_row_buffer.end();
m_hash_map_end = m_row_buffer.end();
return false;

InitProbeIterator(142行~153行)

1、初始化m_probe_input迭代器(为一个RowIterator)

2、判断m_probe_input_batch_mode是否为真(默认为false,指的是不开启批处理模式),为真的话就调用StartPSIBatchMode

  if (m_probe_input->Init()) {return true;}if (m_probe_input_batch_mode) {m_probe_input->StartPSIBatchMode();}return false;

HashJoinIterator 的Init(155行~240行)

1、准备从build(驱动表)输入中读取行数据到哈希表中,用于构建哈希表

  PrepareForRequestRowId(m_build_input_tables.tables(),m_tables_to_get_rowid_for);

函数调用栈:

|PrepareForRequestRowId
||prepare_for_position 

涉及到使用主键去找rows,必须用主键字段扩展读取位图

然后初始化build的迭代器(为一个RowIterator)

2、初始化一些乱七八糟的变量

//默认在内存中做所有操作,并且没有任何对哈希表的重新填充操作。每个输入都只读一次,不会对磁盘写入任何数据。 
m_hash_join_type = HashJoinType::IN_MEMORY;		
//不需要把被驱动表读出来的行数据写到saving files中。因为只有当哈希连接生成块不能完全放到内存中 或者 哈希连接不能延伸到磁盘时,即probe输入行需要多次Read才需要开启probe行保存
m_write_to_probe_row_saving = false;
//很显然此时build迭代器读取的buffer中是有行数据的,当build input数据被消耗掉,停止hash join 迭代器请求更多行
m_build_iterator_has_more_rows = true;
//开启批处理模式
m_probe_input->EndPSIBatchModeIfStarted();
//如过外连接溢出到磁盘上操作,那么probe行可以和我们未看到的build input中的row匹配,若匹配为true。这里默认是内存里操作,所以初始化为false
m_probe_row_match_flag = false;

3、计算build row、probe row 占的内存大小

计算给定表单行数据需要占多大的byte,记录上界,这样之后pack的数据长度总是会比这个长度短。

upper_row_size 为build row、probe row两者的最大值。

  size_t upper_row_size = 0;if (!m_build_input_tables.has_blob_column()) {upper_row_size =hash_join_buffer::ComputeRowSizeUpperBound(m_build_input_tables);}if (!m_probe_input_tables.has_blob_column()) {upper_row_size = std::max(upper_row_size,hash_join_buffer::ComputeRowSizeUpperBound(m_probe_input_tables));}

4、一个看不懂的操作,将一个string类型的变量reverse了一下

if (m_temporary_row_and_join_key_buffer.reserve(upper_row_size)) {my_error(ER_OUTOFMEMORY, MYF(0), upper_row_size);return true;  // oom
}

5、如果一个表包含一个geometry列,确保该数据复制到行缓冲区,而不是只设置指向数据的指针。因为当hash join溢出到磁盘上,需要从块文件读回一行,行数据存储在一个临时缓冲区中,当临时缓冲区用于其他用途时,字段指向的数据将变为无效。

  MarkCopyBlobsIfTableContainsGeometry(m_probe_input_tables);MarkCopyBlobsIfTableContainsGeometry(m_build_input_tables);

6、chunk 数组、标志clear操作

//m_chunk_files_on_disk数组来保存磁盘上的块文件列表,以防我们降级为磁盘上的散列联接.此时需要clear
m_chunk_files_on_disk.clear();
//build 和 probe 当前从hash join chunk中读取的是第0行
m_build_chunk_current_row = 0;
m_probe_chunk_current_row = 0;
//现在不使用任何一种hash join chunk
m_current_chunk = -1;

7、对于每个给定的表,如果需要,请求填写行ID(相当于调用file->position())

 PrepareForRequestRowId(m_probe_input_tables.tables(),m_tables_to_get_rowid_for);

8、构建哈希表

// Build the hash table
if (BuildHashTable()) {DBUG_ASSERT(thd()->is_error() ||thd()->killed);  // my_error should have been called.return true;
}

9、当build 和 probe 都没有row数据了,返回。

  if (m_state == State::END_OF_ROWS) {// BuildHashTable() decided that the join is done (the build input is// empty, and we are in an inner-/semijoin. Anti-/outer join must output// NULL-complemented rows from the probe input).return false;}

10、如果是反连接并且join情况数组为空 并且 没有其他情况并且此时row buffer中仍然有数据。说明此时不需要输出任何东西,因为所有数据都在哈希表中。

  if (m_join_type == JoinType::ANTI && m_join_conditions.empty() &&m_extra_condition == nullptr && !m_row_buffer.empty()) {// For degenerate antijoins, we know we will never output anything// if there's anything in the hash table, so we can end right away.// (We also don't need to read more than one row, but// CreateHashJoinAccessPath() has already added a LIMIT 1 for us// in this case.)m_state = State::END_OF_ROWS;return false;}

11、初始化probe迭代器

return InitProbeIterator();

InitializeChunkFiles(364行~401行)

初始化两个input的hashjoinchunk。

先估计需要多少块,有一个来源是planner估计的。此外可以假设当前行缓冲区代表了总体的行密度,将估计的剩余row数量/目前读到的row数量,就能得到chunk数。

1、缩减后的哈希表中的行 = 缩减因子* 哈希表中行数 这是一种保护措施,因为我们宁愿得到一个或两个额外的块,而不必多次重新读取探测输入。

constexpr double kReductionFactor = 0.9;
const size_t reduced_rows_in_hash_table =std::max<size_t>(1, rows_in_hash_table * kReductionFactor)

2、剩余行数 = max(哈希表中行数,planner估计的join的行数) - 哈希表中的行数

const size_t remaining_rows =std::max(rows_in_hash_table, estimated_rows_produced_by_join) -rows_in_hash_table;

3、 需要的chunk数 = max(剩余行数 / 缩减后的哈希表中的行数)

 const size_t chunks_needed = std::max<size_t>(1, std::ceil(remaining_rows / reduced_rows_in_hash_table));

4、真正的chunk数 = min(最大chunk文件数,需要的chunk数) 限制每个输入的块数,这样就不会冒着达到服务器对打开文件数的限制的风险。

const size_t num_chunks = std::min(max_chunk_files, chunks_needed);

5、确保chunk数目是偶数,因为我们join的时候是按照probe和build的一对chunk进行join的

  const size_t num_chunks_pow_2 = my_round_up_to_next_power(num_chunks);

6、调整chunk数目到偶数;然后对每对chunk进行初始化,一个是buildchunk一个是probechunk

  chunk_pairs->resize(num_chunks_pow_2);for (ChunkPair &chunk_pair : *chunk_pairs) {if (chunk_pair.build_chunk.Init(build_tables, /*uses_match_flags=*/false) ||chunk_pair.probe_chunk.Init(probe_tables,include_match_flag_for_probe)) {my_error(ER_TEMP_FILE_WRITE_FAILURE, MYF(0));return true;}}

对于Init的两个参数解释:

tables – 行数据存储在哪个input
uses_match_flags – 是否应在每行前面加上匹配标志,表示该行是否有匹配行。

InitWritingToProbeRowSavingFile(1115~1119)

标记已经启用probe row saving,并准备probe row saving file以供写入

m_write_to_probe_row_saving = true;return m_probe_row_saving_write_file.Init(m_probe_input_tables,m_join_type == JoinType::OUTER);

至于HashJoinChunk::Init函数我们就不去细究了,它涉及到了IOcache操作。

InitReadingFromProbeRowSavingFile(1121~1126)

标记我们从probe row saving files中读取数据。然后将saving files 倒回开头

m_probe_row_saving_read_file = std::move(m_probe_row_saving_write_file);
m_probe_row_saving_read_file_current_row = 0;
m_read_from_probe_row_saving = true;
return m_probe_row_saving_read_file.Rewind();

1、将write file内容传给read file,同时使用move,避免拷贝赋值,仅仅改动指针指向

2、初始化当前应该读的行数为0,表示还没开始读

3、确定我们应当从probe row saving read files中读取数据

4、Rewind函数将file buffer 清除,准备读的新数据腾出空间

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c语言的宏定义学习笔记

宏定义 在预处理之前&#xff0c;c预处理器会对代码进行翻译&#xff0c;譬如用blank替换注释&#xff0c;去掉多余的空格&#xff0c;删除末尾的\来拼接行等。 例如&#xff1a; int /*注释*/ x; 会被翻译成 int x; printf("this is a s\ entence."); 会被翻译成 pr…

摄氏温度转换华氏温度_什么是摄氏温度?

摄氏温度转换华氏温度摄氏温度 (Celsius) Celsius is a temperature measuring scale which as a SI unit derived from the seven base units stated and described by the International System of Units (SI). 摄氏温度是一种温度测量刻度&#xff0c;它是由国际单位制(SI)所…

别人的算法学习之路

http://www.cnblogs.com/figure9/p/3708351.html 我的算法学习之路 关于 严格来说&#xff0c;本文题目应该是我的数据结构和算法学习之路&#xff0c;但这个写法实在太绕口——况且CS中的算法往往暗指数据结构和算法&#xff08;例如算法导论指的实际上是数据结构和算法导论&a…

git config命令使用第二篇——section操作,多个key值操作,使用正则

接上一篇&#xff0c;git config命令使用第一篇——介绍&#xff0c;基本操作&#xff0c;增删改查:http://blog.csdn.net/hutaoer06051/article/details/8275069 1. 删除一个section 命令参数 --remove-section 格式&#xff1a;git config [--local|--global|--system] --rem…

MySQL面试准备——64页pdf

本笔记为以前整理的零碎的关于Mysql的知识点&#xff0c;有深入源码的也有浅层的八股。已经被我整理成了一个pdf。 实习岗位正好也是和数据库内核有关的&#xff0c;之后应该还会更新。做个整理&#xff0c;方便秋招的时候快速回顾吧。 链接&#xff1a;链接 提取码&#xff1a…

python点图_Python | 点图

python点图The dot plot is a type of data representation in which each data-point in the figure is represented as a dot. Dot plot underlies discrete functions unlike a continuous function in a line plot. Each value could be correlated but cannot be connecte…

SAP-MM:发票、贷方凭证、事后借记、后续贷记

发票和事后借记 相同点&#xff1a;增加对供应商的应付款 不同点&#xff1a;针对同一订单收货&#xff0c;发票要先于事后借记&#xff08;事后借记是对供应商后期发票金额的补充&#xff09;&#xff1b;发票和金额、订单数量有关系&#xff0c;而事后借记只是订单金额调整的…

Dijkstra for MapReduce (1)

<math xmlns"http://www.w3.org/1998/Math/MathML"><mi>x</mi><mo>,</mo><mi>y</mi><mo>&#x2208;<!-- ∈ --></mo><mi>X</mi> </math> 准备研究一下Dijkstra最短路径算法Hadoop上…

sql的外键约束和主键约束_SQL约束

sql的外键约束和主键约束SQL | 约束条件 (SQL | Constraints) Constraints are the guidelines implemented on the information sections of a table. These are utilized to restrict the kind of information that can go into a table. This guarantees the precision and …

nios pio interrupt 的使能

关于nios 中的中断&#xff0c;因为要16c550中需要nios的中断环境去测试&#xff0c;所以就用到了中断。 硬件&#xff1a;在nios中添加硬件PIO,但是要使能中断功能。如下图所示&#xff1a; 系统列化&#xff0c;PIO的连接就不说了。但是要注意两地方&#xff1a;edge type&am…

《单线程的build hash table、write rows to chunks、hash join的步骤以及流程图》

Build Hash Table流程 1、初始化row buffer2、从build input table中读一行3、若读完build input table所有row&#xff0c;返回状态READING_ROW_FROM_PROBE_item4、否则&#xff0c;向hash map中写入一条row5、如果hash map 写入成功&#xff0c;返回2&#xff0c;继续执行6、…

在Scala的溪流

Scala | 流 (Scala | Streams) Stream in Scala is a type of lazy val. It is a lazy val whose elements are evaluated only when they are used in the program. Lazy initialization is a feature of Scala that increases the performance of the program. Scala中的Stre…

适合高速驱动电路的推挽电路

http://www.dzsc.com/data/html/2008-9-10/69023.html 图1是使用NPN/PNP型晶体管的互补推挽电路&#xff0c;适于驱动功率MOSFET的门极。此电路虽然具有门极电流的驱动能力&#xff0c;但射极输出波形不能比输人信号快。 图2是此电路的开关波形。它表示出tf、tr都快&#xff0c…

cholesky分解

接着LU分解继续往下&#xff0c;就会发展出很多相关但是并不完全一样的矩阵分解&#xff0c;最后对于对称正定矩阵&#xff0c;我们则可以给出非常有用的cholesky分解。这些分解的来源就在于矩阵本身存在的特殊的 结构。对于矩阵A&#xff0c;如果没有任何的特殊结构&#xff0…

socket编程常见函数使用方法

socket知识 有了IP地址&#xff0c;socket可知道是与哪一台主机的哪一个进程通信 有了端口号&#xff0c;就知道是这个进程的哪一个套接字进行传输 应用进程使用描述符与它的套接字进行通信&#xff0c;也就是说一个进程创建一个套接字时就会返回一个套接字描述符 socket的…

需求变更流程不规范,项目早晚得完蛋

很多人&#xff0c;做的项目不少&#xff0c;但成功的不多。这是一个值得深思的问题。 项目为什么这么难做&#xff1f;需求蔓延&#xff0c;客户难搞是基本原因。 如何解决上述问题&#xff1a; 1&#xff09;强化需求调研和项目设计在整个项目中的重要性 一般地&#xff0c;需…

html 表格套表格_HTML表格

html 表格套表格A table is a set of rows and columns, which could be created on a webpage in HTML, by <table> tag. The tabular representation of complex data makes it readable. 表格是一组行和列&#xff0c;可以通过<table>标签在HTML网页上创建。 复…

Android判断界面

仿造微信&#xff0c;第一次进入去引导界面&#xff0c;否则进启动界面。 package edu.hpu.init;import edu.hpu.logic.R;import android.app.Activity;import android.content.Intent;import android.content.SharedPreferences;import android.os.Bundle;import android.os.H…

HDU计算机网络系统2021复习提纲

目录计算机网络系统的主要功能TCP/IP模型与OSI模型的层次结构及各层功能。&#xff08;掌握&#xff09;TCP/IP参考模型各层次所对应的主要设备局域网的体系结构与IEEE.802标准数据链路层的编址方式和主要设备原理数据链路层CSMA/CD的技术原理交换机VLAN原理与划分方法数据链路…

ruby 线程id_Ruby中的线程

ruby 线程idRuby线程 (Ruby Threads) In Ruby, with the help of threads, you can implement more than one process at the same time or it can be said that Thread supports concurrent programming model. Apart from the main thread, you can create your thread with …