以如下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.處理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 }
其中outer_join_type對應
1 outer_join_type:
2 LEFT opt_outer JOIN_SYM { $$= JTT_LEFT; }
3 | RIGHT opt_outer JOIN_SYM { $$= JTT_RIGHT; }
入參處理在函式T_joined_table_on內
2.移步到函式PT_joined_table_on
從PT_joined_table_on宣告可知其繼承PT_joined_table函式,入參左右表賦值為PT_joined_table內定義的tr1和tr2
函式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內首先會對當前的執行優化操作,
- 呼叫查詢運算式
Query_expression的優化器unit->optimize,此函式中會對該Query_expression的內的每個查詢塊query_block分別先進行優化操作, - 查詢塊內函式
bool JOIN::optimize()內會將每個查詢塊優化生成查詢執行計劃 ,具體執行函式為函式JOIN::create_access_paths()內create_root_access_path_for_join()函式,以當前查詢為例在函式create_root_access_path_for_join內根據引數條件主要呼叫ConnectJoins函式 - 在函式
ConnectJoins內呼叫FindSubstructure判斷是join型別內連接、外連接、半鏈接等型別 - 根據
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)
- 函式
Query_expression::ExecuteIteratorQuery內主要執行m_root_iterator->Init(),迭代器iterator初始化,當前范例為使用HashJoinIterator型別迭代器,因此對應執行迭代器函式HashJoinIterator::Init() - 執行
m_build_input->Init()來初始右表table句柄,用于下面函式BuildHashTable()內讀取右表資料以便初始化回傳資料存盤表hashtable,值得注意的是BuildHashTable函式內會根據處理流程呼叫SetReadingProbeRowState設定執行狀態用于引導后續迭代器iterator執行流程, - 函式內最后呼叫
InitProbeIterator執行m_probe_input->Init()初始左表table句柄用于下面函式讀取左表資料, - 上面操作完成后執行
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社區助手微信好友,發送驗證資訊加群,

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/508867.html
標籤:其他
上一篇:位元組跳動基于ClickHouse優化實踐之“高可用”
下一篇:MySQL事務隔離級別
