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.pswp.cn/news/377028.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/377028.shtml
英文地址,請注明出處:http://en.pswp.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 …