雲原生資料倉儲AnalyticDB PostgreSQL版的pg_hint_plan外掛程式提供了Hint功能(備註陳述式提示)。Hint功能可以幹預和調優執行計畫,從而提升SQL的執行能力。
版本限制
功能介紹
AnalyticDB PostgreSQL版最佳化器,基於統計資料而非固定的規則,評估SQL語句各種可行的執行運算元的代價並選擇代價最低的組合執行。雖然最佳化器會儘可能選擇最好的執行計畫,但是由於資料潛在的內連關係,最終給出的執行計畫未必適用於當前情境。
pg_hint_plan外掛程式可以用Hint來強制幹預和調優SQL語句的執行計畫,並註冊調優後的SQL語句模板和Hint規則,後續遇到相同SQL語句模板(常數參數數值不同,其它值都相同)的SQL語句將自動產生Hint幹預調優後的執行計畫,從而提高執行效率。
啟用Hint功能
執行以下命令安裝外掛程式以啟用Hint功能:
CREATE EXTENSION pg_hint_plan;僅安裝外掛程式的庫可以使用Hint功能。
支援的Hint
類別 | 格式 | 說明 |
設定語句級GUC參數 |
| 設定最佳化器階段的GUC參數。 目前GUC參數僅在最佳化器階段生效,暫時在其它階段(例如Rewrite和Execute等階段)不生效。
|
掃描方法提示 |
| 強制序列掃描。 |
| 強制TID掃描。 | |
| 強制索引掃描,且允許指定一個索引。 | |
| 強制使用僅索引掃描,且允許指定一個索引。 | |
| 強制使用位元影像索引(Bitmap)掃描。 | |
| 禁用序列掃描。 | |
| 禁用TID掃描。 | |
| 禁用索引掃描。 | |
| 禁用僅索引掃描。 | |
| 禁用位元影像索引掃描。 | |
聯結方法提示 說明 需要配合聯結順序提示共同使用。 |
| 強制使用巢狀迴圈聯結。 |
| 強制使用散列聯結。 | |
| 強制使用合并聯結。 | |
| 禁用巢狀迴圈聯結。 | |
| 禁用散列聯結。 | |
| 禁用合并聯結。 | |
聯結順序提示 |
| 強制定義聯結的順序。 |
| 強制定義聯結的順序和方向。 | |
行號糾正提示 |
| 糾正由指定表組成的聯結結果的行號。 可用的校正方法為絕對值
說明 ROWS修改的是總行數,返回的查詢計劃中顯示的是每個節點平均行數(總行數/節點數量)。 |
當前GUC參數之外的其它Hint僅對查詢最佳化工具(Postgres query optimizer)生效,對ORCA最佳化器不生效。
當前暫時不支援並行程度相關的幹預能力。
樣本如下:
設定語句級GUC參數
最佳化器階段的GUC參數配置,對ORCA最佳化器和查詢最佳化工具均生效。
關閉ORCA最佳化器:
/*+ SET(optimizer off) */EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.val = t2.val;關閉後將不會使用ORCA最佳化器。
啟用ORCA最佳化器:
/*+ SET(optimizer on) */EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.val = t2.val;啟用後將預設使用ORCA最佳化器。資料庫在大多數情況都會使用ORCA最佳化器,只有部分情況(例如單表查詢、過多分區表等)不會使用ORCA最佳化器。
強制啟用ORCA最佳化器:
/*+ SET(optimizer on) SET(rds_optimizer_options 0) */EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.val = t2.val;強制啟用後所有情況均使用ORCA最佳化器。資料庫只有在ORCA最佳化器無法建立計劃時不使用ORCA最佳化器。
強制啟用ORCA最佳化器並關閉ORCA最佳化器的HashJoin能力:
/*+ SET(optimizer on) SET(rds_optimizer_options 0) SET(optimizer_enable_hashjoin off) */EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.val = t2.val;
掃描方法提示
以下內容僅適用查詢最佳化工具,使用前請執行以下命令關閉ORCA最佳化器:
SET optimizer to off;強制t1表進行索引掃描:
/*+ Indexscan(t1) */EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.val = t2.val;禁止對t1表進行索引掃描:
/*+ NoIndexscan(t1) */EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.val = t2.val;強制t1表使用t1_val進行位元影像索引掃描:
/*+ Bitmapscan(t1 t1_val) */EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.val = t2.val;強制t1表進行僅索引掃描(IndexOnlyScan):
/*+ Indexonlyscan(t1) */EXPLAIN SELECT t2.*, t1.val FROM t1 JOIN t2 ON t1.val = t2.val;說明僅索引掃描只有僅掃描索引列時才能使用。
強制t1表進行TID掃描:
/*+ Tidscan(t1) */EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.val = t2.val where t1.ctid = '(1,2)';說明TID掃描只有在表中有TID條件時才能使用。
聯結方法提示和聯結順序提示
以下內容僅適用查詢最佳化工具,使用前請執行以下命令關閉ORCA最佳化器:
SET optimizer to off;聯結時t1為左表,且聯結類型為MergeJoin:
/*+ Leading((t1 t2)) MergeJoin(t1 t2) */EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.val = t2.val;聯結時t1為左表, 且聯結類型為NestLoopJoin:
/*+ Leading((t1 t2)) NestLoop(t1 t2) */EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.val = t2.val;聯結時t1為左表, 且聯結時禁止HashJoin:
/*+ Leading((t1 t2)) NoHashJoin(t1 t2) */EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.val = t2.val;指定t2與t3先進行HashJoin,隨後與t1進行NestLoopJoin:
/*+ Leading(((t2 t3) t1)) HashJoin(t2 t3) NestLoop(t2 t3 t1) */EXPLAIN SELECT * FROM t1, t2, t3 WHERE t1.val = t2.val and t2.val = t3.val;
行號糾正提示
以下內容僅適用查詢最佳化工具,使用前請執行以下命令關閉ORCA最佳化器:
SET optimizer to off;將t1與t2聯結後的總行數擴大100倍:
/*+ Rows(t1 t2 *100) */EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.val = t2.val;將t1與t2聯結後的總行數縮小100倍:
/*+ Rows(t1 t2 *0.01) */EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.val = t2.val;將t1與t2聯結後的總行數增加100行:
/*+ Rows(t1 t2 +100) */EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.val = t2.val;將t1與t2聯結後的總行數減少100行:
/*+ Rows(t1 t2 -100) */EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.val = t2.val;將t1與t2聯結後的總行數修正為100:
/*+ Rows(t1 t2 #100) */EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.val = t2.val;
GUC參數
參數名稱 | 預設值 | 說明 |
pg_hint_plan.enable_hint | on | 是否使用Hint幹預計劃。取值說明:
|
pg_hint_plan.enable_hint_table | off | 是否使用Hint註冊功能。取值說明:
|
pg_hint_plan.jumble_mode | off | 定義是否使用OID來標識SQL參數化語句中的對象,例如表、函數、操作符等。取值說明:
說明 該參數不建議經常切換,切換後將無法識別切換前註冊的規則。 |
pg_hint_plan.parse_messages | info | 控制Parse Hint階段的錯誤資訊的日誌等級。取值如下: error、warning、notice、info、log、debug[1-5]。 |
pg_hint_plan.message_level | log | 控制Hint其它階段的錯誤資訊的日誌等級。取值如下: error、warning、notice、info、log、debug[1-5]。 |
註冊Hint
當希望相同SQL模板的SQL語句自動應用Hint或者當出現SQL語句不方便添加Hint時,您可以將Hint註冊資訊添加至系統資料表hint_plan.hints中。註冊後,後續執行相同SQL語句模板的SQL語句時,會自動產生Hint調優的執行計畫。
hint_plan.hints表結構如下:
列名 | 類型 | 內容 |
id | integer | 註冊Hint規則的標號,預設遞增。 |
norm_query_string | text | SQL語句模板,即去除參數(Param)和常數(Const)的SQL語句。 |
application_name | text | 註冊該Hint規則的應用標識字串,用於多個應用間隔離規則,預設為 application_name列擁有唯一鍵約束。 |
hints | text | 為SQL語句模板註冊的Hint。 hints列擁有唯一鍵約束。 |
query_hash | bigint | SQL語句模板參數化後的Hash值,為標準化SQL的唯一標識。 query_hash列擁有唯一鍵約束。 |
enable | boolean | 控制Hint規則是否可用。同一SQL語句模板只能使用一個Hint規則。 |
prepare_param_strings | text | 註冊的查詢SQL語句為Prepare語句時,記錄其參數。 |
您可以直接查詢hint_plan.hints表,但不建議直接修改該表,如需修改建議使用對應函數進行修改。
以下內容將介紹Hint註冊函數:
SQL語句參數化函數
hint_plan.gp_hint_query_parameterize(<query>, <application_name>)參數
說明
query包含Hint的SQL語句。
application_name註冊該Hint規則的應用標識字串,此處預設留空(
'')。該函數用於擷取帶有Hint的SQL語句的各種參數資訊,返回資訊如下:
參數
說明
query_hashSQL語句模板參數化後的Hash值,為標準化SQL的唯一標識。
norm_query_stringSQL語句模板。
comment_hints語句的注釋。
first_matched_hint_in_table在hint_plan.hints表中與SQL語句模板匹配的注釋。
prepare_param_stringsSQL語句中提取出的參數。
樣本如下:
SELECT * FROM hint_plan.gp_hint_query_parameterize('/*+ MergeJoin(t1 t2) Leading((t1 t2)) */SELECT * FROM t1, t2 WHERE t1.id = t2.id and t1.val < 100 and t2.val > 20;');返回樣本如下:
-[ RECORD 1 ]---------------+-------------------------------------------------------------------------- query_hash | -4733464863014584191 norm_query_string | SELECT * FROM t1, t2 WHERE t1.id = t2.id and t1.val < $1 and t2.val > $2; comment_hints | MergeJoin(t1 t2) Leading((t1 t2)) first_matched_hint_in_table | HashJoin(t1 t2) Leading((t1 t2)) prepare_param_strings | {}Hint註冊函數
hint_plan.insert_hint_table(<query>, <application_name>)參數
說明
query包含Hint的SQL語句。
application_name註冊該Hint規則的應用標識字串,此處預設留空(
'')。使用該函數可以為同一個SQL語句模板註冊不同的Hint規則。當您重複插入SQL語句模板、Hint、應用標識字串相同的Hint規則時,hint_plan.hints表中不會存在多組相同的Hint規則,只會將對應的Hint規則變為true,其它Hint規則變為false。
樣本如下:
SELECT hint_plan.insert_hint_table('/*+ MergeJoin(t1 t2) Leading((t1 t2)) */SELECT * FROM t1, t2 WHERE t1.id = t2.id and t1.val < 100 and t2.val > 1;');返回樣本如下:
insert_hint_table --------------------------------------------------------------------------------------------------------------------------------------------------- (1,"SELECT * FROM t1, t2 WHERE t1.id = t2.id and t1.val < $1 and t2.val > $2;","","MergeJoin(t1 t2) Leading((t1 t2)) ",-4733464863014584191,t,{}) (1 row)Hint修改函數
hint_plan.upsert_hint_table(<query>, <application_name>)參數
說明
query包含Hint的SQL語句。
application_name註冊該Hint規則的應用標識字串,此處預設留空(
'')。如果SQL語句對應的參數模板有可用的Hint,則將hint_plan.hints表中的原Hint替換為
query內建的Hint;如果沒有可用的Hint,則新註冊的Hint規則。樣本如下:
查詢hint_plan.hints表中現有的Hint規則:
SELECT * FROM hint_plan.hints;返回資訊如下:
id | norm_query_string | application_name | hints | query_hash | enable | prepare_param_strings ----+---------------------------------------------------------------------------+------------------+------------------------------------+----------------------+--------+----------------------- 1 | SELECT * FROM t1, t2 WHERE t1.id = t2.id and t1.val < $1 and t2.val > $2; | | MergeJoin(t1 t2) Leading((t1 t2)) | -4733464863014584191 | f | {} 2 | SELECT * FROM t1, t2 WHERE t1.id = t2.id and t1.val < $1 and t2.val > $2; | | Nestloop(t1 t2) Leading((t1 t2)) | -4733464863014584191 | t | {} (2 rows)執行Hint修改函數:
SELECT hint_plan.upsert_hint_table('/*+ HashJoin(t1 t2) Leading((t1 t2)) */SELECT * FROM t1, t2 WHERE t1.id = t2.id and t1.val < 100 and t2.val > 1;');返回資訊如下:
upsert_hint_table -------------------------------------------------------------------------------------------------------------------------------------------------- (2,"SELECT * FROM t1, t2 WHERE t1.id = t2.id and t1.val < $1 and t2.val > $2;","","HashJoin(t1 t2) Leading((t1 t2)) ",-4733464863014584191,t,{}) (1 row)查詢修改Hint規則後的hint_plan.hints表:
SELECT * FROM hint_plan.hints;可以看到同SQL語句模板的Hint從
Nestloop(t1 t2) Leading((t1 t2))變成了HashJoin(t1 t2) Leading((t1 t2)),返回資訊如下:id | norm_query_string | application_name | hints | query_hash | enable | prepare_param_strings ----+---------------------------------------------------------------------------+------------------+------------------------------------+----------------------+--------+----------------------- 1 | SELECT * FROM t1, t2 WHERE t1.id = t2.id and t1.val < $1 and t2.val > $2; | | MergeJoin(t1 t2) Leading((t1 t2)) | -4733464863014584191 | f | {} 2 | SELECT * FROM t1, t2 WHERE t1.id = t2.id and t1.val < $1 and t2.val > $2; | | HashJoin(t1 t2) Leading((t1 t2)) | -4733464863014584191 | t | {} (2 rows)
Hint刪除函數
刪除對應ID的Hint規則:
hint_plan.delete_hint_table(<id>)刪除對應SQL語句,Hint,應用標識字串的Hint規則:
hint_plan.delete_hint_table(<query>, <hint>, <application_name>)刪除所有對應SQL語句,應用標識字串的Hint規則:
hint_plan.delete_all_hint_table(<query>, <application_name>)
參數
說明
idhint_plan.hints表中的標號(ID)。
querySQL語句,可以不包含Hint。
hintHint。
application_name註冊該Hint規則的應用標識字串,此處預設留空(
'')。樣本如下:
查詢原hint_plan.hints表資訊:
SELECT * FROM hint_plan.hints;返回資訊如下:
id | norm_query_string | application_name | hints | query_hash | enable | prepare_param_strings ----+---------------------------------------------------------------------------+------------------+-------------------------------------------------+----------------------+--------+----------------------- 1 | SELECT * FROM t1, t2 WHERE t1.id = t2.id and t1.val < $1 and t2.val > $2; | | MergeJoin(t1 t2) Leading((t1 t2)) | -4733464863014584191 | f | {} 2 | SELECT * FROM t1, t2 WHERE t1.id = t2.id and t1.val < $1 and t2.val > $2; | | HashJoin(t1 t2) Leading((t1 t2)) | -4733464863014584191 | t | {} 3 | select * from t1 join t2 on t1.val = t2.val; | | set(optimizer on) set(rds_optimizer_options 0) | -2169095602568752481 | f | {} 4 | select * from t1 join t2 on t1.val = t2.val; | | set(optimizer off) | -2169095602568752481 | t | {} (4 rows)根據ID刪除對應的Hint規則:
SELECT hint_plan.delete_hint_table(1);返回資訊如下:
WARNING: "max_appendonly_tables": setting is deprecated, and may be removed in a future release. delete_hint_table --------------------------------------------------------------------------------------------------------------------------------------------------- (1,"SELECT * FROM t1, t2 WHERE t1.id = t2.id and t1.val < $1 and t2.val > $2;","","MergeJoin(t1 t2) Leading((t1 t2)) ",-4733464863014584191,f,{}) (1 row)查詢刪除後的hint_plan.hints表:
SELECT * FROM hint_plan.hints;返回資訊如下:
id | norm_query_string | application_name | hints | query_hash | enable | prepare_param_strings ----+---------------------------------------------------------------------------+------------------+-------------------------------------------------+----------------------+--------+----------------------- 2 | SELECT * FROM t1, t2 WHERE t1.id = t2.id and t1.val < $1 and t2.val > $2; | | HashJoin(t1 t2) Leading((t1 t2)) | -4733464863014584191 | t | {} 3 | select * from t1 join t2 on t1.val = t2.val; | | set(optimizer on) set(rds_optimizer_options 0) | -2169095602568752481 | f | {} 4 | select * from t1 join t2 on t1.val = t2.val; | | set(optimizer off) | -2169095602568752481 | t | {} (3 rows)根據SQL語句、Hint和應用標識字串刪除對應的Hint規則:
SELECT hint_plan.delete_hint_table('SELECT * FROM t1, t2 WHERE t1.id = t2.id and t1.val < 5 and t2.val > 1;', 'HashJoin(t1 t2) Leading((t1 t2))');返回資訊如下:
delete_hint_table -------------------------------------------------------------------------------------------------------------------------------------------------- (2,"SELECT * FROM t1, t2 WHERE t1.id = t2.id and t1.val < $1 and t2.val > $2;","","HashJoin(t1 t2) Leading((t1 t2)) ",-4733464863014584191,t,{}) (1 row)查詢刪除後的hint_plan.hints表:
SELECT * FROM hint_plan.hints;返回資訊如下:
id | norm_query_string | application_name | hints | query_hash | enable | prepare_param_strings ----+----------------------------------------------+------------------+-------------------------------------------------+----------------------+--------+----------------------- 3 | select * from t1 join t2 on t1.val = t2.val; | | set(optimizer on) set(rds_optimizer_options 0) | -2169095602568752481 | f | {} 4 | select * from t1 join t2 on t1.val = t2.val; | | set(optimizer off) | -2169095602568752481 | t | {} (2 rows)根據SQL語句、應用標識字串刪除對應的Hint規則:
SELECT hint_plan.delete_all_hint_table('select * from t1 join t2 on t1.val = t2.val;');返回資訊如下:
delete_all_hint_table ----------------------------------------------------------------------------------------------------------------------------------- (3,"select * from t1 join t2 on t1.val = t2.val;","","set(optimizer on) set(rds_optimizer_options 0) ",-2169095602568752481,f,{}) (4,"select * from t1 join t2 on t1.val = t2.val;","","set(optimizer off) ",-2169095602568752481,t,{}) (2 rows)查詢刪除後的hint_plan.hints表:
SELECT * FROM hint_plan.hints;返回資訊如下:
id | norm_query_string | application_name | hints | query_hash | enable | prepare_param_strings ----+-------------------+------------------+-------+------------+--------+----------------------- (0 rows)
Hint使能函數
啟用對應ID的Hint規則,啟用後同SQL語句模板的其它Hint規則將不可用:
hint_plan.enable_hint_table(<id>)啟用對應SQL語句,Hint,應用標識字串的Hint規則,啟用後同SQL語句模板的其它Hint規則將不可用:
hint_plan.enable_hint_table(<query>, <hint>, <application_name>)禁止對應ID的Hint規則:
hint_plan.disable_hint_table(<id>)禁止對應SQL語句,Hint,應用標識字串的Hint規則:
hint_plan.disable_hint_table(<query>, <hint>, <application_name>)禁止對應SQL語句,應用標識字串的Hint規則:
hint_plan.disable_all_hint_table(<query>, <application_name>)
參數
說明
idhint_plan.hints表中的標號(ID)。
querySQL語句,可以不包含Hint。
hintHint規則。
application_name註冊該Hint規則的應用標識字串,此處預設留空(
'')。樣本如下:
查詢原hint_plan.hints表資訊:
SELECT * FROM hint_plan.hints;返回資訊如下:
id | norm_query_string | application_name | hints | query_hash | enable | prepare_param_strings ----+----------------------------------------------+------------------+-------------------------------------------------+----------------------+--------+----------------------- 5 | select * from t1 join t2 on t1.val = t2.val; | | set(optimizer off) | -2169095602568752481 | f | {} 6 | select * from t1 join t2 on t1.val = t2.val; | | set(optimizer on) set(rds_optimizer_options 0) | -2169095602568752481 | t | {} (2 rows)禁止對應ID的Hint規則:
SELECT hint_plan.disable_hint_table(6);返回資訊如下:
disable_hint_table ----------------------------------------------------------------------------------------------------------------------------------- (6,"select * from t1 join t2 on t1.val = t2.val;","","set(optimizer on) set(rds_optimizer_options 0) ",-2169095602568752481,f,{}) (1 row)查詢變更狀態後的hint_plan.hints表:
SELECT * FROM hint_plan.hints;返回資訊如下:
id | norm_query_string | application_name | hints | query_hash | enable | prepare_param_strings ----+----------------------------------------------+------------------+-------------------------------------------------+----------------------+--------+----------------------- 5 | select * from t1 join t2 on t1.val = t2.val; | | set(optimizer off) | -2169095602568752481 | f | {} 6 | select * from t1 join t2 on t1.val = t2.val; | | set(optimizer on) set(rds_optimizer_options 0) | -2169095602568752481 | f | {} (2 rows)啟用對應ID的Hint規則:
SELECT hint_plan.enable_hint_table(5);返回資訊如下:
enable_hint_table ------------------------------------------------------------------------------------------------------- (5,"select * from t1 join t2 on t1.val = t2.val;","","set(optimizer off) ",-2169095602568752481,t,{}) (1 row)查詢變更狀態後的hint_plan.hints表:
SELECT * FROM hint_plan.hints;返回資訊如下:
id | norm_query_string | application_name | hints | query_hash | enable | prepare_param_strings ----+----------------------------------------------+------------------+-------------------------------------------------+----------------------+--------+----------------------- 6 | select * from t1 join t2 on t1.val = t2.val; | | set(optimizer on) set(rds_optimizer_options 0) | -2169095602568752481 | f | {} 5 | select * from t1 join t2 on t1.val = t2.val; | | set(optimizer off) | -2169095602568752481 | t | {} (2 rows)根據SQL語句、應用標識字串啟用對應的Hint規則:
SELECT hint_plan.enable_hint_table('select * from t1 join t2 on t1.val = t2.val;', 'set(optimizer off)');返回資訊如下:
enable_hint_table ------------------------------------------------------------------------------------------------------- (5,"select * from t1 join t2 on t1.val = t2.val;","","set(optimizer off) ",-2169095602568752481,t,{}) (1 row)查詢變更狀態後的hint_plan.hints表:
SELECT * FROM hint_plan.hints;返回資訊如下:
id | norm_query_string | application_name | hints | query_hash | enable | prepare_param_strings ----+----------------------------------------------+------------------+-------------------------------------------------+----------------------+--------+----------------------- 6 | select * from t1 join t2 on t1.val = t2.val; | | set(optimizer on) set(rds_optimizer_options 0) | -2169095602568752481 | f | {} 5 | select * from t1 join t2 on t1.val = t2.val; | | set(optimizer off) | -2169095602568752481 | t | {} (2 rows)
卸載pg_hint_plan外掛程式
如果您不需要使用Hint功能,可以通過以下語句卸載外掛程式:
DROP EXTENSION pg_hint_plan;