mysql 优化器关联查询_MySQL 查询优化器(二)
1.6多個查詢字段(常量條件)
多個查詢字段的查詢處理邏輯如下所示:
JOIN:prepare階段
setup_tables():同1.1測試。
setup_fields():同1.1測試。
setup_conds():同1.4測試。
JOIN:optimize階段
optimize_cond():類似1.4測試,不同之處在于查詢的where條件中有恒等常量,在優化過程中會調用remove_eq_conds將1=1條件刪除。
make_join_statistics():與1.4測試類似,由于where條件查詢有兩個,并且其中一個條件可以通過索引查詢。因此首先通過調用update_ref_and_keys()(sql\sql_select.cc:3967)函數,查找可以使用索引的字段。
SQL_SELECT::test_quick_select():同1.5索引測試
get_key_scans_params():同1.5索引測試。
choose_plan():同1.3測試。
greedy_search():同1.3測試。
best_extension_by_limited_search():同1.5索引測試。
JOIN:exec階段
以下操作同1.3測試。
通過測試可以看出,對于常量等式對查詢優化器來說沒有任何意義,會在optimize_conds時將常量等式刪除。建議在查詢的where條件中不要出現對查詢沒有意義的條件,盡管查詢優化器會將沒有意義的查詢條件去除,并等式的右值條件盡可能的轉化為常量,例如將類似(a=b, b=1)類型轉化為(a=1, b=1)。但從優化角度來看,盡可能在sql語句中就避免這些優化邏輯。查詢計劃的類型為ref,利用索引查找。
查詢student中多個普通字段(包含常量條件),執行SQL:
SELECT?std_id,?std_name,?std_spec,?std_***,?std_age?FROM?student?WHERE?std_name="fff"?AND?std_age?>?20?AND?1=1;
對應的查詢計劃如下所示:
查詢計劃跟單個查詢條件的索引查詢的執行相同,這說明增加非索引字段的查詢,主要用于從索引查詢的結果中過濾記錄。如果添加的索引不能過濾掉大多數的查詢記錄的話,普通查詢條件過濾記錄的代價也會較大。因此,建立索引的目的應該是盡可能的過濾掉查詢記錄,那么增加索引才有效,否則索引查詢反而會增加查詢的代價。
1.7 LIMIT條件
Limit條件查詢的邏輯處理流程如1.5普通條件查詢類似,唯一不同點在于JOIN::exec()處理過程中,取結果集時,根據limit限制的值來進行過濾。因此,當查詢結果集較多的情況下,limit條件可以減少結果集傳遞的代價。
查詢student中limit條件,執行SQL:
SELECT?std_id,?std_name,?std_spec,?std_***,?std_age?FROM?student?WHERE?std_spec?=?"computer"?LIMIT?5;
1.8 IN條件
In條件查詢的邏輯處理流程如下所示:
JOIN:prepare階段
setup_tables():同1.1測試。
setup_fields():同1.1測試。
setup_conds():同1.4測試。
JOIN:optimize階段
optimize_cond():同1.4測試。
make_join_statistics():與1.5索引測試類似,不同之處在于調用update_ref_and_keys()(sql\sql_select.cc:3967)函數時,查找查詢字段是否可以用索引字段時,沒有找到可以使用的索引。但是由于查詢字段上有索引,因此調用get_quick_record_count()函數的實現邏輯SQL_SELECT::test_quick_select()函數構建查詢樹時,轉化為OR的方式處理,并將查找的鍵值進行合并,形成查詢范圍。
SQL_SELECT::test_quick_select():同1.5索引測試
get_key_scans_params():同1.5索引測試。
choose_plan():同1.3測試。
greedy_search():同1.3測試。
best_extension_by_limited_search():同1.5測試。盡管查詢字段有索引,但是調用update_ref_and_keys()對查詢字段進行檢查是否可以使用索引時,沒有可以使用的索引。因此,不同于1.5的索引測試的過程,而是與普通查詢測試相同。
JOIN:exec階段
以下操作類似1.3測試。不同之處在于查詢的范圍通過搜索查詢樹,減小了查詢的范圍。
查詢student中in條件(索引),執行SQL:
SELECT?std_id,?std_name,?std_spec,?std_***,?std_age?FROM?student?WHERE?std_name?in?("bbb","ccc","ddd");
對應的查詢計劃如下所示:
從邏輯處理過程和查詢計劃可以看出,IN條件的處理是轉化為OR的條件來處理,這一點從查詢樹的構建可以看出。查詢計劃類型為range,沒有使用索引直接查詢,而是通過索引查找來構建查詢樹,減小查詢的范圍。
IN條件的查詢字段為普通字段時,由于查詢字段無索引,因此,不會通過調用get_quick_record_count()函數的實現邏輯SQL_SELECT::test_quick_select()函數構建查詢樹,從而形成查詢范圍。而是直接執行JOIN::exec中進行全表掃描,通過查詢條件過濾查詢結果。
查詢student中in條件(普通字段),執行SQL:
SELECT?std_id,?std_name,?std_spec,?std_***,?std_age?FROM?student?WHERE?std_spec?in?("math","information");
對應的查詢計劃如下所示:
通過查詢計劃可以看出,對沒有索引的字段使用IN操作跟普通的1.5的普通字段查詢測試相同。
通過對IN條件的整體測試發現,當查詢的字段存在索引的情況下,查詢優化器會利用查詢字段的索引,構建查詢樹,減小查詢的范圍,然后通過查詢優化數進行全掃描并返回查詢結果。而在查詢字段沒有索引的情況下,查詢計劃和查詢邏輯跟普通查詢條件進行全表掃描一樣,在執行全表掃描時,通過查詢條件過濾查詢結果。
1.9 GROUP BY條件、ORDER BY條件、HAVING條件聯合
之所以將三個條件聯合查詢,而非單獨測試,是由于這些條件一般都是組合使用才有效果。并且,單獨測試不會凸顯查詢條件的全部處理邏輯,不利于更好的理解。
具體的查詢處理邏輯如下所示:
JOIN:prepare階段
setup_tables():同1.1測試。
setup_fields():同1.1測試。
setup_conds():同1.4測試。
setup_order():初始化order by列表。根據order by的字段,改變查詢列表中查詢字段的order by順序。并調用find_order_in_list()函數,檢查order by 的字段是否在select的字段中(調用find_item_in_list(),(sql\sql_base.cc:6835)),并查找order by列表中的字段是否在數據表中 (調用find_item_in_tables(),(sql\sql_base.cc:6602))。(sql\sql_select.cc:15037)(sql\sql_select.cc:14996)
setup_group():初始化group by列表,處理邏輯跟setup_order()的處理邏輯相同。調用find_order_in_list()函數,檢查group by 的字段是否在select的字段中(調用find_item_in_list(),(sql\sql_base.cc:6835)),并查找group by列表中的字段是否在數據表中 (調用find_item_in_tables(),(sql\sql_base.cc:6602))。(sql\sql_select.cc:15037)(sql\sql_select.cc:14996)
having處理:having的初始化過程沒有以具體的函數形式給出,但是處理邏輯類似group by。主要檢查having條件的字段是否在查詢列表中。由于having條件是查詢字段的別名,因此在比較了查詢列表后,發現該字段即結束。
JOIN:optimize階段
optimize_cond():類似1.4測試,但不同之處在于進行優化的是having條件。
make_join_statistics():與1.3轉化為group by后的測試類似。
choose_plan():同1.3測試。
greedy_search():同1.3測試。
best_extension_by_limited_search():同1.3測試。
calc_group_buffer():同1.3測試。
create_tmp_table():同1.3測試。
JOIN:exec階段
以下操作同1.3測試類似,區別在于對臨時表操作時,臨時結果的過濾方式不同。生成臨時結果的過程中,會調用聚合函數進行處理。
從處理邏輯來看,在JOIN::prepare階段增加了初始化group、order、having條件。由于查詢字段沒有索引,因此需要進行全表掃描。與普通查詢不同的執行過程在于在臨時表操作時,臨時結果的過濾處理不同。
查詢student中group by、order by、having聯合條件,執行SQL:
SELECT?std_spec,?COUNT(std_spec)?cnt?FROM?student?GROUP?BY?std_spec?HAVING?cnt?>?3?ORDER?BY?cnt;
對應的查詢計劃如下所示:
從查詢計劃來看,與1.3測試完全一致。查詢計劃類型為ALL,進行全表掃描。
1.10 UNION條件
Union條件的查詢處理邏輯如下所示:
mysql_union():Union條件處理邏輯。調用st_select_lex_unit::prepare()函數(sql\sql_union.cc:1172)對Union中的每條語句進行處理。
st_select_lex_unit::prepare():逐條執行JOIN:prepare()處理邏輯,為查詢處理做準備工作,并調用select_union::create_result_table()(sql\sql_union.cc:117)函數創建臨時表。
JOIN:prepare階段:主要處理過程同1.4測試。
st_select_lex_unit::exec():逐條執行JOIN:optimize()處理邏輯,對每條查詢語句進行優化。逐條執行JOIN:exec()處理邏輯,執行查詢操作。
JOIN:optimize階段:對于Union中的不同查詢字段類型的語句,處理邏輯有所不同。Union的第一句的處理邏輯同1.4主鍵查詢測試。Union的第二句的處理邏輯同1.5測試的索引字段處理。Union的第三句的處理邏輯同1.5測試的普通字段處理。
JOIN:exec階段:對不同的Union中不同查詢字段類型的語句,處理邏輯不同,并將查詢的結果存儲到臨時表中。同JOIN:optimize階段的對應關系相同。
st_select_lex_unit::init_prepare_fake_select_lex():構建一條查詢語句,獲取查詢結果。
mysql_select():同1.1測試,獲取查詢結果。
從處理邏輯來看,UNION條件的處理相當于分別對不同的查詢子句根據對應的查詢條件類型進行處理。處理結束后,對分別的查詢結果再次進行查詢過濾。
查詢student中union條件,執行SQL:
SELECT?std_id,?std_name,?std_spec,?std_***,?std_age?FROM?student?WHERE?std_id=2012072306?UNION?SELECT?std_id,?std_name,?std_spec,?std_***,?std_age?FROM?student?WHERE?std_name="bbb"?UNION?SELECT?std_id,?std_name,?std_spec,?std_***,?std_age?FROM?student?WHERE?std_spec="math";
對應的查詢計劃如下所示:
從查詢計劃來看,查詢類型根據UNION中各個子句的查詢字段類型,生成各自的查詢計劃。最后對查詢結果,進行進一步的過濾查詢。
總結
以上是生活随笔為你收集整理的mysql 优化器关联查询_MySQL 查询优化器(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php 远程下载大文件,php下载远程文
- 下一篇: java之父_java之父:被下载达70