云数据库 PostgreSQL pg_hint_plan

这篇说说pg_hint_plan插件,通过SQL注释提示控制优化器的执行计划,支持强制指定扫描方式、连接方式和行数估计,用于优化器选择不当的场景。 扫描方式提示:支持SeqScan、IndexScan等强制改变扫描类型。 连接方式提示:支持NestLoop、HashJoin等强制改变连接方式。 行数估计提示:通过Rows调整连接结果行数估计值。

相关产品
云数据库 PostgreSQL 产品页,含版本规格、价格与购买入口。

这里说明 pg_hint_plan 插件的简介及使用方法。

一、概述

pg_hint_plan 是执行计划提示插件,通过在 SQL 语句中添加特殊注释控制优化器的执行计划,可强制指定扫描方式、连接方式、行数估计等,适用于优化器选择不当需要人工干预的场景。

二、支持版本

PostgreSQL 版本 内核版本
PostgreSQL 10 v10.23_r1.20及以上
PostgreSQL 11 v11.22_r1.35及以上
PostgreSQL 12 v12.22_r1.37及以上
PostgreSQL 13 v13.22_r1.32及以上
PostgreSQL 14 v14.22_r1.42及以上
PostgreSQL 15 v15.14_r1.27及以上
PostgreSQL 16 v16.10_r1.22及以上
PostgreSQL 17 v17.9_r1.16及以上
PostgreSQL 18 v18.1_r1.5及以上

注意:说明:

注意:你可在控制台实例详情页查看当前实例的内核版本,或执行 SHOW tencentdb_version; 查询。

三、插件简介

pg_hint_plan 通过 SQL 注释形式的提示(hint)干预执行计划的生成,例如 /*+ SeqScan(t) */ 强制顺序扫描、/*+ NestLoop(a b) */ 强制嵌套循环连接。提示只影响当前语句,不改变数据库对象。

四、创建扩展

在目标数据库中执行以下语句创建扩展:

postgres=> CREATE EXTENSION pg_hint_plan;CREATE EXTENSION

注意:说明:

注意:pg_hint_plan 的扩展安装在 hint_plan 模式下,创建时需要当前数据库的 CREATE 权限,请使用具备建库权限的账号在对应数据库执行。

五、扫描方式提示

以下示例创建测试表并查看默认执行计划:

postgres=> CREATE TABLE hint_test(id int PRIMARY KEY, val int);CREATE TABLEpostgres=> INSERT INTO hint_test SELECT i, i FROM generate_series(1, 10000) AS i;INSERT 0 10000postgres=> ANALYZE hint_test;ANALYZEpostgres=> EXPLAIN (COSTS OFF) SELECT * FROM hint_test WHERE id = 5000; QUERY PLAN—————————— Index Scan using hint_test_pkey on hint_test Index Cond: (id = 5000)(2 rows)

默认情况下,等值条件查询走主键索引扫描。

六、强制顺序扫描

使用 SeqScan 提示强制全表顺序扫描:

postgres=> EXPLAIN (COSTS OFF) SELECT /*+ SeqScan(hint_test) */ * FROM hint_test WHERE id = 5000; QUERY PLAN——————— Seq Scan on hint_test Filter: (id = 5000)(2 rows)

注意:说明:

注意:执行计划由默认的索引扫描变为顺序扫描,提示生效。

七、指定索引扫描

使用 IndexScan 提示指定扫描方式与索引:

postgres=> EXPLAIN (COSTS OFF) SELECT /*+ IndexScan(t hint_test_pkey) */ * FROM hint_test t WHERE t.id = 5000; QUERY PLAN———————————————— Index Scan using hint_test_pkey on hint_test t Index Cond: (id = 5000)(2 rows)

八、连接方式提示

以下示例创建第二张表并查看默认连接计划:

postgres=> CREATE TABLE hint_dept(id int PRIMARY KEY, dname text);CREATE TABLEpostgres=> INSERT INTO hint_dept VALUES (1,'dev'), (2,'ops'), (3,'qa');INSERT 0 3postgres=> ANALYZE hint_dept;ANALYZEpostgres=> EXPLAIN (COSTS OFF) SELECT * FROM hint_test t JOIN hint_dept d ON t.val = d.id; QUERY PLAN——————————- Hash Join Hash Cond: (t.val = d.id) -> Seq Scan on hint_test t -> Hash -> Seq Scan on hint_dept d(5 rows)

默认连接方式为 Hash Join。使用 NestLoop 提示强制嵌套循环连接:

postgres=> EXPLAIN (COSTS OFF) SELECT /*+ NestLoop(t d) */ * FROM hint_test t JOIN hint_dept d ON t.val = d.id; QUERY PLAN——————————- Nested Loop Join Filter: (d.id = t.val) -> Seq Scan on hint_test t -> Materialize -> Seq Scan on hint_dept d(5 rows)

注意:说明:

注意:连接方式由 Hash Join 变为 Nested Loop,提示生效。

九、行数估计提示

使用 Rows 提示调整连接结果的行数估计,影响优化器的代价计算:

postgres=> EXPLAIN SELECT /*+ Rows(t d #10) */ * FROM hint_test t JOIN hint_dept d ON t.val = d.id; QUERY PLAN———————————————————————– Hash Join (cost=1.07..172.33 rows=10 width=15) Hash Cond: (t.val = d.id) -> Seq Scan on hint_test t (cost=0.00..145.00 rows=10000 width=8) -> Hash (cost=1.03..1.03 rows=3 width=7) -> Seq Scan on hint_dept d (cost=0.00..1.03 rows=3 width=7)(5 rows)

注意:说明:

注意:Rows(t d #10) 将连接结果行数估计指定为10(# 表示绝对值),实际估计值由默认的3行调整为10行。也可用 +n(加值)、-n(减值)、*n(倍数)方式调整。

十、常用提示速查

提示 说明
SeqScan(表) 强制顺序扫描
IndexScan(表 [索引]) 强制索引扫描,可指定索引名
BitmapScan(表 [索引]) 强制位图扫描
NestLoop(表1 表2) 强制嵌套循环连接
HashJoin(表1 表2) 强制哈希连接
MergeJoin(表1 表2) 强制合并连接
Rows(表1 表2 #n) 调整连接行数估计
Leading(表1 表2) 指定连接顺序

十一、Q:使用 Rows 提示时报 Rows hint requires at least two relations?

A:Rows 提示用于调整连接结果的行数估计,需要至少指定两个关系。单表的行数估计暂不支持通过该提示调整。

十二、Q:提示写在什么位置?

A:提示写在 SQL 语句的注释中,格式为 /*+ 提示内容 */,紧跟在 SELECT、UPDATE、DELETE 等关键字之后。提示语法错误时会输出 INFO 级别日志但不影响语句执行。

十三、相关参考

pg_hint_plan 产品文档

赞 (0)
上一篇 4天前
下一篇 4天前