摘要:路徑生成是表關聯方式肯定的主要階段,本文介紹了幾個影響路徑生成的要素:cost_param, scan方式,join方式,stream方式,並從原理上分析如何幹預路徑的生成。
1、cost模型選擇
顧名思義,cost_param是控制cost相關的一個參數。在瞭解cost_param以前,先回顧一下選擇率的概念,GaussDB優化器中的選擇率是指,當一個表有一個過濾或關聯條件時,經過該條件能被選中的行數佔總行數的比例,是介於0~1之間的一個實數。選擇率在優化器中是一個重要的概念,主要應用於行數和distinct值的估算,行數和distinct值是計劃生成中的基本要素。redis
首先,咱們來看帶有過濾條件的基錶行數如何估算。若是一個表只有一個過濾條件,那麼以選擇率乘以表的行數,便可獲得過濾完的行數;若是有多個過濾條件,那麼就須要算出一個綜合的選擇率,如何計算?方式有二:一是經過多列統計信息直接計算,二是經過組合單列的選擇率。那麼組合的方式就由參數cost_param決定了,具體地,網絡
舉一個例子,TPC-H 1x的part表,過濾條件是:p_brand = 'Brand#45' and p_container = 'WRAP CASE',查看不一樣cost_param下的過濾後行數。分佈式
(1)cost_param=0oop
(2)cost_param=2性能
從估算出的行數(E-rows)和實際的行數(A-rows)對比能夠看出,cost_param=0的不相關模型適合part表的p_brand和p_container列。優化
其次,Join的行數怎麼估算的呢?原理跟過濾條件的行數估算是相似的,若是沒有多列統計信息可使用,則也須要單獨計算每一個條件的選擇率,而後計算出綜合選擇率,得出行數。例如 TPC-H 1x lineitem和orders關聯,關聯條件是:l_orderkey = o_orderkey and o_custkey = l_suppkey,不一樣cost_param的執行狀況以下:url
(1)cost_param=0spa
(2)cost_param=2.net
此例中,Join的列之間也適合徹底相關模型,這與l_orderkey和l_suppkey的分佈是吻合的。3d
因爲TPC-H的模型接近徹底不相關模型,所以cost_param=0模型能夠較好的描述場景,實際應用中,用戶能夠根據具體業務場景來調整模型,行數估算的準確性是計劃生成的重要保證,在調優中檢查估算的最直接的地方。GaussDB會在後續版本中新增更多的模型供業務需求選擇。
2、Scan方式的選擇
GaussDB中掃描方式主要分順序掃描和索引掃描,每種掃描方式都對應若干掃描算子,順序掃描在行列存中對應的掃描算子分別是Seq Scan和CStore Scan算子(下面咱們討論中不加區分)。這些掃描算子大部分均可以經過開關來進行調控,例如Seq Scan,若是設置enable_seqscan=off,則表示不會優先選擇Seq Scan,而不是必定不會選。掃描方式的選擇,很大程度上決定了獲取基表數據的路徑。咱們以以下的例子來講明:
select l_orderkey, o_custkey from lineitem, orders where l_orderkey = o_orderkey;
lineitem分佈鍵是l_orderkey,而且在l_orderkey上有index,orders分佈鍵是o_orderkey。默認狀況下,Scan的方式以下:
兩個表都是順序掃描的路徑,關聯方式選擇了Hash Join。若是把Seq Scan關掉(enable_seqscan=off),計劃以下:
lineitem的掃描變成了Index Only Scan(由於l_orderkey的類型是int),而在orders表上仍然選擇Seq Scan(由於沒有其餘路徑),同時關聯方式也變爲了Nest Loop,由於Hash Join須要全表掃描數據(lineitem的Seq Scan已經被關掉了)。優化器的選擇方式咱們從代價(E-costs)一欄中也能夠看出。再把Index Only Scan關掉,看看計劃如何變化:
掃描路徑都變爲了Seq Scan,並且Seq Scan的代價都很大。此時既然都走了Seq Scan,爲何不選Hash Join呢,把Nest Loop關掉,看看Hash Join計劃的代價:
從代價上看出Hash Join的總代價比Nest Loop的小,但優化器沒有選擇Hash Join,這是由於優化器比較路徑代價時,會比較Startup和Total代價,即啓動代價和總代價,綜合考慮,E-costs欄中顯示的是總代價。把explain_perf_mode設置爲normal,查看原Nest Loop的啓動代價:
紅框中的兩個cost,分別是啓動代價和總代價,在看Hash Join的cost,明顯Hash Join的啓動代價比Nest Loop的大不少(啓動代價表明了輸出第一條數據的代價),優化器在比較路徑時,綜合了這兩個代價,最終推薦了Nest Loop的路徑。
從上面的例子能夠看出,掃描路徑的調控,能夠改變路徑生成,合理的搭配是生成最優計劃的前提,默認狀況下,GaussDB優化器能夠根據現有的路徑選擇(如上面的lineitem有兩條掃描路徑,orders只有一條掃描路徑),最後肯定出最優的一條。兩條路徑代價比較時,總代價不是惟一要素,但總代價越小,通常也會越容易被選中。
3、關聯方式的選擇
GaussDB優化器中表關聯的主要方式有:Nest Loop,Hash Join和Merge Join,分別能夠經過enable_nestloop、enable_hashjoin、enable_mergejoin進行控制,這種控制也不是絕對的,能夠理解爲是否優先選擇。大部分場景下,三種路徑的代價關係:Hash Join < Merge Join < Nest Loop。咱們以一個簡單的關聯示例說明,store_returns和store_sales是TPC-DS 1x中兩個表,SQL以下:
select count(*) from store_returns, store_sales where sr_customer_sk = ss_customer_sk;
默認狀況下,優化器推薦Hash Join路徑,計劃以下:
若是把Hash Join關掉,則優化器選擇了Merge Join路徑:
若是再把Merge Join路徑關掉,可能就會選擇Nest Loop路徑。關聯方式的控制開關通常用於調優或規避問題,但具體是否可以起做用要看具體的語句,除了當前關聯方式,還有沒有其餘方式。實際場景中,一個語句中關聯的算子較多,通常很難用參數enable_hashjoin或enable_nestloop或enable_mergejoin來控制某兩個表的Join方式,GaussDB中更細緻的語句級別的調優手段是Plan Hint,感興趣的讀者能夠參考產品手冊。
4、Stream方式的選擇
Stream算子是GaussDB分佈式執行的關鍵算子之一,主要起到網絡傳輸的做用, 概要介紹能夠參考:GaussDB(DWS)性能調優系列實戰篇一:十八般武藝之整體調優策略。 Stream算子由參數enable_stream_operator控制,若是關掉Stream算子,則可能致使生成不下推的計劃,例如:
由於lineitem表關聯的鍵l_partkey不是lineitem的分佈鍵,須要添加Stream算子,但Stream功能被禁,因而只能生成不下推計劃。
GaussDB計劃中常見的主要Stream算子包括Redistribute、Broadcast和Gather。Gather通常是分佈式計劃中,CN用於收集DN的數據進行最後的處理,除非最後收集的行數很是多,這個算子涉及性能問題通常較少。Redistribute和Broadcast一是對「互補」的算子,前者用於重分佈,後者用於廣播,生成計劃時,優化器會根據代價大小來選擇。當Join Key沒有包含表的分佈鍵的時候,通常會添加Redistribute路徑,能選擇Redistribute路徑理論上也可選擇Broadcast路徑,最終選擇哪條路徑要看優化器估算的代價是多少。這兩個算子能夠經過參數enable_redistribute和enable_broadcast進行控制。
在SMP開啓的狀況下,當並行度(dop)大於1時,通常還會有Local Redistribute、Split Redistribute、Local Broadcast和Split Broadcast;當傾斜優化開啓時,還有PART REDISTRIBUTE PART ROUNDROBIN、PART_REDISTRIBUTE_PART_BROADCAST、PART_REDISTERIBUTE_PART_LOCAL等等,這些也是Stream算子,主要就是重分佈、廣播、RoundRobin的一些擴展形式,這裏咱們不一一介紹了,感興趣的讀者能夠參考GaussDB DWS 產品手冊。
咱們考慮兩個表的簡單關聯,store_sales和sr_tbl,它們的分佈鍵分別是ss_item_sk 和sr_returned_date_sk,Join 條件是store_sales.ss_customer_sk =sr_tbl. sr_customer_sk,執行結果以下:
因爲兩個表的分佈鍵都不是Join Key,所以走Hash Join路徑的話須要有一個表作Broadcast或者兩個表都作Redistribute,可是store_sales表比較大(E-rows顯示28.7億行),而sr_tbl錶行數估算比較少(E-rows顯示100行),優化器認爲適合作Broadcast。因而最終選擇了一邊Broadcast的計劃。
對於這個計劃,因爲sr_tbl表統計信息不許確(若是是中間結果集,則表示中間結果集估算不許),一種調優的方法是,將sr_tbl的表統計信息從新收集準確一些(若是sr_tbl是中間結果集,則沒法收集),另外一種方法是讓sr_tbl走Redistribute路徑,然後者咱們又有兩種方式來實現,一是用Plan Hint,即在生成計劃時,告訴優化器走Redistribute路徑,二是把Broadcast關掉。禁用Broadcast後,執行計劃以下:
本列中,開啓了SMP自適應,即優化器會根據系統資源和當前Active SQL數量來自行決定並行度(dop),若是Redistribute和Broadcast選擇不當,則可能致使
(1)Broadcast計劃會出現下盤
(2)兩個計劃的並行度不同,最終執行時間可能會差別比較大。
對於Stream方式的控制,通常的調優方式有Plan Hint、GUC參數、改善統計信息或估算信息。
5、結束語
本文介紹的cost_param屬於cost底層參數,建議對數據特徵和使用場景比較熟悉的DBA慎重使用。Scan、Join、Stream調控的基本依據也是代價,代價通常體如今執行耗時上,調優時可從Performance中識別出性能的瓶頸點,分析選擇的算子是否與代價匹配。另外,除了本文介紹的Session級別的控制參數外,還有基表、中間結果的行數,也能夠經過Plan Hint進行語句級別的調控,感興趣讀者可經過GaussDB DWS產品文檔進一步瞭解。
本文分享自華爲雲社區《GaussDB(DWS)性能調優系列實戰篇五:十八般武藝之路徑干預》,原文做者:- 大道至簡 - 。