Outline Hint
功能描述
Outline是描述执行计划的重要手段,也是计划固化的持久化表示。Outline存储在数据库中,需要在不同版本之间兼容,可以指导优化器生成指定计划。内核在生成执行计划的同时,可以生成Outline。同时优化器能够使用Outline对计划进行控制,Outline是计划管理的核心前提能力。
Outline Hint是优化器为了完全复现某一计划而生成的一组hint信息,以BEGIN_OUTLINE_DATA开始,并以END_OUTLINE_DATA结束。Outline Hint可以通过explain(outline on)获得。使用获得的Outline Hint能够对计划进行控制。
特性约束
- 使用之前需要设置set explain_perf_mode = pretty选项。
- Outline用于计划的复现还原,目前Outline可以控制同一条SQL的如下方面:
- 目前内核的bitmapscan、indexscan、index Hint指定优化器在扫描相关表时,使用指定的索引产生索引扫描路径,具体的索引条件由优化器根据代价生成。
- 对于复杂多表连接的SQL,outline固定计划还原时,性能优于遗传算法。
- 当有Outline Hint时,对于在BEGIN OUTLINE和END OUTLINE包含以外的hint,若为控制计划生成的hint则全部失效处理(2,3,4点所提及的hint),若非控制计划生成的hint则保留,如wlmrule慢SQL管控规则的hint。
语法格式
Outline Hint也是hint的一种,遵循hint的语法。
BEGIN_OUTLINE_DATA VERSION(@version_num) END_OUTLINE_DATA
参数说明
- @version_num:Outline的版本。不指定默认为1.0.0,当前仅支持1.0.0,为后续版本Outline行为控制做预留。
- BEGIN_OUTLINE_DATA/END_OUTLINE_DATA:生成的Outline Hint,在使用时需要放在两者之间。
- BEGIN_OUTLINE_DATA和END_OUTLINE_DATA必须成对使用。
- 当同时使用BEGIN_OUTLINE_DATA和END_OUTLINE_DATA时,只有两者之间的hint会生效。
使用说明
- 生成Outline Hint
SET explain_perf_mode = pretty;
explain (Outline on):
--创建表 gaussdb=# CREATE TABLE ot_t1(a int, b int); gaussdb=# CREATE TABLE ot_t2(a int, b int); --执行 gaussdb=# EXPLAIN (OUTLINE ON, COSTS OFF) SELECT * FROM ot_t1 JOIN ot_t2 ON ot_t1.a = ot_t2.a; id | operation ----+----------------------------- 1 | -> Hash Join (2,3) 2 | -> Seq Scan on ot_t1 3 | -> Hash 4 | -> Seq Scan on ot_t2 (4 rows) Predicate Information (identified by plan id) ----------------------------------------------- 1 --Hash Join (2,3) Hash Cond: (ot_t1.a = ot_t2.a) (2 rows) ====== Outline Data ===== ----------------------------------------------------------------- begin_outline_data HashJoin(@"sel$1" public.ot_t1@"sel$1" public.ot_t2@"sel$1") Leading(@"sel$1" (public.ot_t1@"sel$1" public.ot_t2@"sel$1")) TableScan(@"sel$1" public.ot_t1@"sel$1") TableScan(@"sel$1" public.ot_t2@"sel$1") version("1.0.0") end_outline_data (7 rows)
- 上述Outline data由一系列hint组成。关于hint和hint中查询块的指定功能,遵循原有hint能力。
- BEGIN_OUTLINE_DATA和END_OUTLINE_DATA分别表示Outline的开始和结束。
- HashJoin(@"sel$1" t1@"sel$1" t2@"sel$1")表示在第一个查询块(只有一个查询块),对t1(t1原处于sel$1查询块),t2(t2原处于sel$1查询块)进行HashJoin运算,Leading(@"sel$1" (t1@"sel$1" t2@"sel$1"))表示连接顺序,TableScan(@"sel$1" t1@"sel$1"),TableScan(@"sel$1" t2@"sel$1")表示t1和t2表都进行了顺序扫描。
- Outline能够和计划对应。
- 目前版本号固定为("1.0.0")。
- Outline Hint的使用
在Outline使用时,会使用Outline转换而成的SQL。
gaussdb=# EXPLAIN (OUTLINE ON, COSTS OFF) SELECT /*+ BEGIN_OUTLINE_DATA HashJoin(@"sel$1" public.ot_t1@"sel$1" public.ot_t2@"sel$1") Leading(@"sel$1" (public.ot_t1@"sel$1" public.ot_t2@"sel$1")) TableScan(@"sel$1" public.ot_t1@"sel$1") TableScan(@"sel$1" public.ot_t2@"sel$1") VERSION("1.0.0") END_OUTLINE_DATA */ * FROM ot_t1 JOIN ot_t2 ON ot_t1.a = ot_t2.a; id | operation ----+----------------------------- 1 | -> Hash Join (2,3) 2 | -> Seq Scan on ot_t1 3 | -> Hash 4 | -> Seq Scan on ot_t2 (4 rows) Predicate Information (identified by plan id) ----------------------------------------------- 1 --Hash Join (2,3) Hash Cond: (ot_t1.a = ot_t2.a) (2 rows) ====== Outline Data ===== ----------------------------------------------------------------- begin_outline_data HashJoin(@"sel$1" public.ot_t1@"sel$1" public.ot_t2@"sel$1") Leading(@"sel$1" (public.ot_t1@"sel$1" public.ot_t2@"sel$1")) TableScan(@"sel$1" public.ot_t1@"sel$1") TableScan(@"sel$1" public.ot_t2@"sel$1") version("1.0.0") end_outline_data (7 rows)
对比1,2可以看到两个计划完全相同,说明可以用Outline Hint控制计划的生成。
- 对比非Outline Hint计划
- 普通的hint:
gaussdb=# EXPLAIN (OUTLINE ON, COSTS OFF) SELECT /*+ NestLoop(@"sel$1" ot_t1@"sel$1" ot_t2@"sel$1") Leading(@"sel$1" (ot_t1@"sel$1" ot_t2@"sel$1")) TableScan(@"sel$1" ot_t1@"sel$1") TableScan(@"sel$1" ot_t2@"sel$1") */ * FROM ot_t1 JOIN ot_t2 ON ot_t1.a = ot_t2.a; id | operation ----+----------------------------- 1 | -> Nested Loop (2,3) 2 | -> Seq Scan on ot_t1 3 | -> Materialize 4 | -> Seq Scan on ot_t2 (4 rows) Predicate Information (identified by plan id) ----------------------------------------------- 1 --Nested Loop (2,3) Join Filter: (ot_t1.a = ot_t2.a) (2 rows) ====== Outline Data ===== ----------------------------------------------------------------- begin_outline_data NestLoop(@"sel$1" public.ot_t1@"sel$1" public.ot_t2@"sel$1") Leading(@"sel$1" (public.ot_t1@"sel$1" public.ot_t2@"sel$1")) TableScan(@"sel$1" public.ot_t1@"sel$1") Materialize_Inner(@"sel$1" public.ot_t2@"sel$1") TableScan(@"sel$1" public.ot_t2@"sel$1") version("1.0.0") end_outline_data (8 rows)
- Outline Hint:
gaussdb=# EXPLAIN (OUTLINE ON, COSTS OFF) SELECT /*+ BEGIN_OUTLINE_DATA NestLoop(@"sel$1" ot_t1@"sel$1" ot_t2@"sel$1") Leading(@"sel$1" (ot_t1@"sel$1" ot_t2@"sel$1")) TableScan(@"sel$1" ot_t1@"sel$1") TableScan(@"sel$1" ot_t2@"sel$1") VERSION("1.0.0") END_OUTLINE_DATA */ * from ot_t1 join ot_t2 on ot_t1.a = ot_t2.a; id | operation ----+-------------------------- 1 | -> Nested Loop (2,3) 2 | -> Seq Scan on ot_t1 3 | -> Seq Scan on ot_t2 (3 rows) Predicate Information (identified by plan id) ----------------------------------------------- 1 --Nested Loop (2,3) Join Filter: (ot_t1.a = ot_t2.a) (2 rows) ====== Outline Data ===== ----------------------------------------------------------------- begin_outline_data NestLoop(@"sel$1" public.ot_t1@"sel$1" public.ot_t2@"sel$1") Leading(@"sel$1" (public.ot_t1@"sel$1" public.ot_t2@"sel$1")) TableScan(@"sel$1" public.ot_t1@"sel$1") TableScan(@"sel$1" public.ot_t2@"sel$1") version("1.0.0") end_outline_data (7 rows)
可以看到,普通的hint只指定了部分行为,并不能完全固定计划。
示例a中,普通hint产生了Materialize计划,该计划并不在hint中。
示例b中,Outline Hint没有产生Materialize计划,完整地固化了计划。
- 普通的hint: