MySQL 查詢優化器(四)

2.5 LEFT JOIN查詢mysql

    該測試主要用於測試LEFT JOIN與JOIN的處理邏輯上的差別,具體查詢處理邏輯以下所示:sql

JOIN:prepare階段函數

setup_tables():同2.1測試。測試

setup_fields():同2.1測試。優化

setup_conds():同2.4測試。spa

JOIN:optimize階段指針

simplify_joins():相似2.4測試。不一樣之處在於因爲LEFT JOIN 使用的數據表不能爲 NULL表,這是由是否有where條件過濾決定的。因此該過程會將LEFT JOIN外連接查詢轉化爲多表聯合查詢操做,從而忽略LEFT JOIN的連接操做。code

optimize_cond():同2.1測試。orm

make_join_statistics():同2.4測試。ci

choose_plan():同2.1測試。

greedy_search():同2.1測試。

best_extension_by_limited_search():同2.4測試。

get_best_combination():同2.4測試。

JOIN:exec階段

如下同2.4測試。

 Left join嵌套(join)查詢執行SQL:

SELECT student.std_id, std_name, std_spec, std_***, std_age, cur_name, cur_credit, cur_hours, score FROM student LEFT JOIN(course JOIN std_cur ON std_cur.cur_id=course.cur_id) ON (student.std_id=std_cur.std_id) WHERE course.cur_name = 'C';

對應的查詢計劃以下所示:

經過以上測試發現,除了在simplify_joins()處有略微的不一樣以外,其餘處理邏輯和查詢計劃與測試2.4都是同樣的。而LEFT JOIN從理論來講,會將左邊的表的進行全表掃描,而右邊的表中若是沒有匹配的記錄時,會用NULL值填充。而後從查詢結果來看,查詢的記錄並不是student表的全部記錄。而且從查詢計劃來看,student表的查詢類型不是ALL

經過查看simplify_joins()函數的註釋和源碼實現發現,OUTER JOIN能夠轉化爲INNER JOIN,轉化的條件與used_tablesnot_null_tables的值有關。而not_null_tables的值是根據where條件決定的。若是有where條件過濾,那麼LEFT JOIN會被轉化爲INNER JOIN查詢。更進一步的研究,將做爲單獨的問題進行詳細的研究和測試。

2.6 Natural JOIN查詢

    Natural JOIN的查詢處理邏輯以下所示:

JOIN:prepare階段

setup_tables():相似2.1測試,不一樣之處在於調用setup_natural_join_row_types()函數將Natural JOIN查詢轉化爲JOIN ON查詢。轉化過程爲:找到共同的字段名,做爲ON的條件進行連接查詢。

setup_fields():同2.1測試。

setup_conds():同2.3測試。

JOIN:optimize階段

simplify_joins():同2.3測試。

optimize_cond():同2.1測試。

make_join_statistics():同2.3測試。

choose_plan():同2.1測試。

greedy_search():同2.1測試。

best_extension_by_limited_search():同2.3測試。

get_best_combination():同2.3測試。

JOIN:exec階段

如下同2.3測試。

Natural join查詢執行SQL:

 SELECT student.std_id, std_name, std_spec, std_***, std_age, cur_name, cur_credit, cur_hours, score FROM student NATURAL JOIN std_cur NATURAL JOIN course WHERE course.cur_id = 101;

對應的查詢計劃以下所示:

由以上查詢處理邏輯和查詢計劃能夠看出,Natural JOIN查詢處理與JOIN ON的處理方式相似。惟一不一樣之處在set_tables()處理階段,調用setup_natural_join_row_types()函數將Natural JOIN查詢轉化爲JOIN ON查詢。從官方文檔中能夠知道,Natural JOIN也說明了該查詢的處理邏輯[1]。應用中,Natural JOIN查詢有其侷限性,必須有相同的字段名,才能使用。所以,在查詢處理中,應避免使用不明確的字段進行聯合查詢,使用用明確的字段進行連接,不但可以獲取到正確的查詢結果,並且能夠避免MySQL額外的查詢處理邏輯。

2.7 Straight_JOIN查詢

    STRAIGHT_JOIN查詢是是 MySQL 對標準 SQL 的擴展,用於在多表查詢時指定表載入的順序。具體的查詢處理邏輯以下所示:

JOIN:prepare階段

setup_tables():同2.1測試,

setup_fields():同2.1測試。

setup_conds():同2.3測試。

JOIN:optimize階段

simplify_joins():相似2.3測試,不一樣之處在於根據STRAIGHT_JOIN的條件,爲數據表創建依賴關係,也就是說右部的表依賴於左部的表。一樣,轉化爲JOIN的查詢處理。

optimize_cond():同2.1測試。

make_join_statistics():同2.3測試。

choose_plan():同2.1測試。

greedy_search():同2.1測試。

best_extension_by_limited_search():相似2.3測試,不一樣之處在於根據表的依賴關係,查找最優的查詢計劃。因爲右部的表依賴於左部的表,所以在組合查找最優路徑時,右部的表必須始終在左部的表的後面。

get_best_combination():同2.3測試。

JOIN:exec階段

如下同2.3測試。

因爲STRAIGHT_JOIN的查詢與表的順序有關係,爲了體現這一特色,測試兩條不一樣表順序的SQL語句進行比較查詢計劃的不一樣。

Straight_join查詢執行SQL:

SELECT student.std_id, std_name, std_spec, std_***, std_age, cur_name, cur_credit, cur_hours, score FROM student STRAIGHT_JOIN(course STRAIGHT_JOIN std_cur ON std_cur.cur_id=course.cur_id) ON (student.std_id=std_cur.std_id) WHERE course.cur_name = 'C';

第一條SQL查詢對應的查詢計劃以下所示:


執行SQL:

SELECT student.std_id, std_name, std_spec, std_***, std_age, cur_name, cur_credit, cur_hours, score FROM student STRAIGHT_JOIN(std_cur STRAIGHT_JOIN course ON std_cur.cur_id=course.cur_id) ON (student.std_id=std_cur.std_id) WHERE course.cur_name = 'C';

第二條SQL查詢對應的查詢計劃以下所示:

    經過以上查詢處理邏輯來看,STRAIGHT_JOIN與JOIN查詢相似,不一樣之處在於將STRAIGHT_JOIN轉化爲表的依賴關係,從而限制查找最優查詢計劃過程當中表的組合方式,而沒有直接調用函數optimize_straight_join() (sql\sql_select.cc:5108)來取代greedy_search()函數的優化。

    此外,從查詢計劃來看,第一個SQL查詢沒有按照指定的表的順序執行,這是由於指定的student表和course表沒有關聯關係,轉化爲JOIN查詢處理,經過查詢優化器計算的代價來決定student加載的順序。而course表與std_cur表存在關聯關係,因此會按照course表首先加載,std_cur表後加載。而從第二個SQL查詢來看,徹底按照指定表的順序進行加載。

2.8 子查詢

    在SQL查詢中有子查詢時,查詢處理邏輯就遠遠不是以上處理邏輯了,查詢處理過程的入口函數爲execute_sqlcom_select()(sql\sql_parse.cc:4530)。由於從該函數開始,就已經對子查詢進行處理。固然以前的查詢處理也都從該函數入口,可是以前的查詢在該過程當中並無特殊的處理,而且主要分析查詢優化器的處理邏輯,所以沒有就該部分作過多的分析。

    具體的查詢處理邏輯以下所示:

execute_sqlcom_select():查詢入口函數。因爲子查詢中的表tmp不是實際的表,所以,會首先對子查詢進行處理。首先調用open_and_lock_tables()函數打開查詢中的全部表並添加鎖。其次調用handle_select()函數處理查詢處理。

open_and_lock_tables():該函數用於打開SQL查詢中的表,並添加鎖。此外,還會處理驅動表。調用open_tables()函數打開全部的表,lock_tables()函數爲全部表添加鎖,調用mysql_handle_derived()函數處理驅動表。而對子查詢來講,特殊的處理邏輯爲調用mysql_handle_derived()處理驅動表的過程。(sql\sql_base.cc:5494)

mysql_handle_derived():用於處理驅動表,實際處理過程根據給定的函數指針,執行對應的處理階段。首先調用mysql_derived_prepare()函數中的處理邏輯,準備子查詢的處理邏輯;其次調用mysql_derived_filling()函數處理子查詢中的優化和執行的處理邏輯;最後調用mysql_derived_cleanup()函數清理子查詢使用的資源。(sql\sql_derived.cc:46)

mysql_derived_prepare():用於準備子查詢的處理邏輯過程。從查詢處理過程來看,MySQL將子查詢做爲一個查詢子單元(unit)來看,共用了union的查詢邏輯處理過程。調用st_select_lex_unit::prepare()函數(sql\sql_union.cc:172),執行JOIN::prepare階段,查詢處理邏輯相似2.1測試,不一樣之處是group條件的處理過程,相似測試1.9。調用select_union::create_result_table()函數(sql\sql_union.cc:117)建立臨時表,調用create_tmp_table()函數執行具體的建立過程。(sql\sql_derived.cc:135)

mysql_derived_filling():處理子查詢優化和執行的處理邏輯。調用mysql_select()函數實際進行查詢的處理邏輯,因爲已經執行了prepare過程。所以,該過程主要處理JOIN::optimize階段,優化過程的處理邏輯相似2.1測試,對group條件的處理過程(須要建立臨時表,存儲臨時結果),相似測試1.9。處理JOIN::exec階段,執行過程的處理邏輯相似2.1測試,不一樣之處在於查詢結果存儲到prepare階段建立的臨時表中。(sql\sql_derived.cc:264)

mysql_derived_cleanup():清理子查詢使用的資源。調用st_select_lex_unit::cleanup()函數進行具體的清理工做。(sql\sql_derived.cc:321)

handle_select():主查詢過程的實際處理邏輯,查詢處理過程相似2.1測試多表聯合查詢處理方式,不一樣之處是聯合查詢四個表,其中tmp爲子查詢處理過程當中獲得的臨時表。

子查詢執行SQL:

SELECT student.std_id, std_name, student.std_spec, std_***, std_age, SUM(cur_credit) total FROM student, course, std_cur, (SELECT std_spec, AVG(score) savg FROM student LEFT JOIN std_cur ON (student.std_id = std_cur.std_id) GROUP BY std_spec) tmp WHERE student.std_id = std_cur.std_id AND course.cur_id = std_cur.cur_id AND student.std_spec = tmp.std_spec AND score > tmp.savg GROUP BY std_id ORDER BY total;

對應的查詢計劃以下所示:

從以上查詢處理邏輯來看,子查詢的處理邏輯與以前的處理有所不一樣,其入口函數的層次有所提高,而且處理的流程也發生了變化。對子查詢來講,首先根據查詢條件和查詢的表得到子查詢語句中的結果集,該過程的查詢處理做爲union中的一個單元來處理。處理邏輯與單獨的查詢處理過程相似,最後將查詢的結果集存儲到臨時表中。而後執行多表聯合查詢,得到最終的查詢結果。

       從查詢計劃來看,特別之處是select_type的值爲PRIMARYDERIVED,其中PRIMARY表示爲最外的查詢;DERIVED表示驅動表查詢,依賴於外部的查詢。所以,select_typeDERIVED的是查詢獲取驅動表的查詢計劃,select_typePRIMARY的是主查詢的查詢計劃。

相關文章
相關標籤/搜索