版本限制
V6.3.8.1以及上核心版本支援安裝pg_hint_plan外掛程式後預設啟用Hint功能。
V6.3.8.1之前核心版本建議升級至V6.3.8.1及以上版本後再安裝pg_hint_plan外掛程式。
V6.3.8.9及以上版本,安裝或升級外掛程式需要提交工單聯絡支援人員進行處理。
如何查看和升級核心小版本,請參見查看核心小版本和版本升級。
功能介紹
AnalyticDB PostgreSQL版最佳化器,基於統計資料而非固定的規則,評估SQL語句各種可行的執行運算元的代價並選擇代價最低的組合執行。雖然最佳化器會儘可能選擇最好的執行計畫,但是由於資料潛在的內連關係,最終給出的執行計畫未必適用於當前情境。
pg_hint_plan外掛程式可以用Hint來強制幹預和調優SQL語句的執行計畫,並註冊調優後的SQL語句模板和Hint規則,後續遇到相同SQL語句模板(常數參數數值不同,其它值都相同)的SQL語句將自動產生Hint幹預調優後的執行計畫,從而提高執行效率。
啟用Hint功能
執行以下命令安裝外掛程式以啟用Hint功能:
CREATE EXTENSION pg_hint_plan;
支援的Hint
類別 | 格式 | 說明 |
設定語句級GUC參數 | Set(GUC-param value)
| 設定最佳化器階段的GUC參數。 目前GUC參數僅在最佳化器階段生效,暫時在其它階段(例如Rewrite和Execute等階段)不生效。 |
掃描方法提示 | SeqScan(table)
| 強制序列掃描。 |
TidScan(table)
| 強制TID掃描。 |
IndexScan(table[ index...])
| 強制索引掃描,且允許指定一個索引。 |
IndexOnlyScan(table[ index...])
| 強制使用僅索引掃描,且允許指定一個索引。 |
BitmapScan(table[ index...])
| 強制使用位元影像索引(Bitmap)掃描。 |
NoSeqScan(table)
| 禁用序列掃描。 |
NoTidScan(table)
| 禁用TID掃描。 |
NoIndexScan(table)
| 禁用索引掃描。 |
NoIndexOnlyScan(table)
| 禁用僅索引掃描。 |
NoBitmapScan(table)
| 禁用位元影像索引掃描。 |
聯結方法提示 | NestLoop(table table[ table...])
| 強制使用巢狀迴圈聯結。 |
HashJoin(table table[ table...])
| 強制使用散列聯結。 |
MergeJoin(table table[ table...])
| 強制使用合并聯結。 |
NoNestLoop(table table[ table...])
| 禁用巢狀迴圈聯結。 |
NoHashJoin(table table[ table...])
| 禁用散列聯結。 |
NoMergeJoin(table table[ table...])
| 禁用合并聯結。 |
聯結順序提示 | Leading(table table[ table...])
| 強制定義聯結的順序。 |
Leading(<join pair>)
| 強制定義聯結的順序和方向。 |
行號糾正提示 | Rows(table table[ table...] correction)
| 糾正由指定表組成的聯結結果的行號。 可用的校正方法為絕對值#<n> 、加法+ <n> 、減法-<n> 和乘法* <n> 。 <n> 是strtod函數可以讀取的數字。
說明 ROWS修改的是總行數,返回的查詢計劃中顯示的是每個節點平均行數(總行數/節點數量)。 |
樣本如下:
GUC參數
參數名稱 | 預設值 | 說明 |
pg_hint_plan.enable_hint | on | 是否使用Hint幹預計劃。取值說明: on:開啟Hint幹預計劃。 off:關閉Hint幹預計劃。
|
pg_hint_plan.enable_hint_table | off | 是否使用Hint註冊功能。取值說明: on:開啟Hint註冊功能。 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_hash
| SQL語句模板參數化後的Hash值,為標準化SQL的唯一標識。 |
norm_query_string
| SQL語句模板。 |
comment_hints
| 語句的注釋。 |
first_matched_hint_in_table
| 在hint_plan.hints表中與SQL語句模板匹配的注釋。 |
prepare_param_strings
| SQL語句中提取出的參數。 |
樣本如下:
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_plan.hints表中的標號(ID)。 |
query
| SQL語句,可以不包含Hint。 |
hint
| Hint。 |
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)
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>)
參數 | 說明 |
id
| hint_plan.hints表中的標號(ID)。 |
query
| SQL語句,可以不包含Hint。 |
hint
| Hint規則。 |
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;