十八般武藝玩轉GaussDB(DWS)性能調優:Plan hint運用

前言redis

數據庫的使用者在書寫SQL語句時,會根據本身已知的狀況盡力寫出性能很高的SQL語句。可是當須要寫大量SQL語句,且有些SQL語句的邏輯極爲複雜時,數據庫使用者就很難寫出性能較高的SQL語句。數據庫

而每一個數據庫都有一個相似人的大腦的查詢優化器模塊,它接收來自語法分析模塊傳遞過來的查詢樹,在這個查詢樹的基礎上進行邏輯上的等價變換、物理執行路徑的篩選,而且把選擇出的最優的執行路徑傳遞給數據庫的執行器模塊。查詢優化器是提高查詢效率很是重要的一個手段。oop

數據庫查詢優化器的分類詳見博文性能

Plan hint的引入測試

因爲優化器基於統計信息和估算模型生成計劃,當估算出現誤差時,計劃可能出現問題,性能較差,使語句的執行變得奇慢無比。優化

一般,查詢優化器的優化過程對數據庫使用者是透明的。 在上一篇博文中, Gauss DB(DWS)提供了可經過配置GUC參數的方式,全局的干預查詢計劃的路徑生成。本次,將介紹另外一種能夠人工干預計劃生成的功能--plan hint。Hint是一種經過SQL語句中的註釋傳遞給優化器的指令,優化器使用hint爲語句選擇執行計劃。在測試或開發環境中,hint對於測試特定訪問路徑的性能很是有用。例如,您可能知道某些表優先進行鏈接,能夠有效減小中間結果集大小,在這種狀況下,可使用提示來指示優化器使用更好的執行計劃。網站

Plan hint功能屬於語句級的調控,僅對當前語句的當前層次生效,能夠幫助咱們在調優的過程當中,針對特定的語句,經過plan hint進行人工干預,選擇更高效的執行計劃。.net

GaussDB(DWS)的Plan hint有如下種類:orm

Join順序的hint:調整join順序索引

Scan/Join方法的hint:指定或避免scan/join的方法

Stream方法的hint:指定或避免redistribute/broadcast

行數hint:對於給定結果集,指定行數,或對原有估算值進行計算調整

傾斜值hint:在傾斜優化時,指定須要傾斜處理的特殊值

下面分別對以上幾種plan hint的功能及其在實際中的運用作一下介紹。在下面幾節的介紹中,除傾斜值hint外,都以tpcds中的Q6做爲示例。爲了能明顯看到hint在查詢優化過程當中的做用,咱們將store_sales表的統計信息刪除。原始語句和生成的初始計劃以下。

示例語句:

explain performanceselect a.ca_state state, count(*) cnt

from customer_address a

,customer c

,store_sales s

,date_dim d

,item i

where a.ca_address_sk = c.c_current_addr_sk

and c.c_customer_sk = s.ss_customer_sk

and s.ss_sold_date_sk = d.d_date_sk

and s.ss_item_sk = i.i_item_sk

and d.d_month_seq =

(select distinct (d_month_seq)

from date_dim

where d_year = 2000

and d_moy = 2 )

and i.i_current_price > 1.2 *

(select avg(j.i_current_price)

from item j

where j.i_category = i.i_category)

group by a.ca_state

having count(*) >= 10

order by cnt

limit 100;

Plan hint的應用

Join 順序的hint

語法:

格式1:

leading(table_list)

僅指定join順序,不指定內外表順序

格式2:

leading((table_list))

同時指定join順序和內外表順序,內外表順序僅在最外層生效

說明:

table_list爲要調整join順序的表名列表,表之間使用空格分隔。能夠包含當前層的任意個表(別名),或對於子查詢提高的場景,也能夠包含子查詢的hint別名,同時任意表可使用括號指定優先級。

注意:

表只能用單個字符串表示,不能帶schema。

表若是存在別名,須要優先使用別名來表示該表。

list中的表在當前層或提高的子查詢中必須是惟一的。若是不惟一,須要使用不一樣的別名進行區分。

同一個表只能在list裏出現一次。

示例1:

對於示例中的計劃,能夠看出,17-22號算子時store_sales表和item表join後生成hash表,store_sales表的數據量很大,store_sales和item表join後未過濾掉任何數據,因此這兩個表join並生成hash表的時間都比較長。根據對tpcds各表中數據分佈的瞭解,咱們知道,store_sales表和date_dim進行join,能夠過濾掉網站監控較多數據,因此,可使用hint來提示優化器優將store_sales表和date_dim表先進行join,store_sales做爲外表,date_dim做爲內表,減小中間結果集大小。語句改寫以下:

explain performanceselect /+ leading((s d)) / a.ca_state state, count(*) cnt

from customer_address a

,customer c

,store_sales s

,date_dim d

,item i

where a.ca_address_sk = c.c_current_addr_sk

and c.c_customer_sk = s.ss_customer_sk

and s.ss_sold_date_sk = d.d_date_sk

and s.ss_item_sk = i.i_item_sk

and d.d_month_seq =

(select distinct (d_month_seq)

from date_dim

where d_year = 2000

and d_moy = 2 )

and i.i_current_price > 1.2 *

(select avg(j.i_current_price)

from item j

where j.i_category = i.i_category)

group by a.ca_state

having count(*) >= 10

order by cnt

limit 100;

經過調整join順序,使得以後各join的中間結果集都大幅減小,執行時間由34268.322ms降爲11095.046ms。

Scan/Join方法的hint

用於指示優化器使用那種scan方法或join方法。

語法:

Join方法的hint格式:

[no] nestloop|hashjoin|mergejoin(table_list)

Scan方法的hint格式:

[no] tablescan|indexscan|indexonlyscan(table [index])

說明:

no表示提示優化器不使用這種方法。

table表示hint指定的表,只能指定一個表,若是表存在別名應優先使用別名進行hint。

index表示使用indexscan或indexonlyscan的hint時,指定的索引名稱,當前只能指定一個。

示例2-1:

示例1中獲得的執行計劃,因爲store_sales表的行數估算不許,store_sales和date_dim採用了效率很差的nestloop方式進行join。如今經過本節的hint方法來指示優化器不使用nestloop方式進行join。

explain performanceselect /+ leading((s d)) no nestloop(s d) / a.ca_state state, count(*) cnt

from customer_address a

,customer c

,store_sales s

,date_dim d

,item i

where a.ca_address_sk = c.c_current_addr_sk

and c.c_customer_sk = s.ss_customer_sk

and s.ss_sold_date_sk = d.d_date_sk

and s.ss_item_sk = i.i_item_sk

and d.d_month_seq =

(select distinct (d_month_seq)

from date_dim

where d_year = 2000

and d_moy = 2 )

and i.i_current_price > 1.2 *

(select avg(j.i_current_price)

from item j

where j.i_category = i.i_category)

group by a.ca_state

having count(*) >= 10

order by cnt

limit 100;

相關文章
相關標籤/搜索