前言
在pg_hint_plan技术内幕–02 Scan method中我们介绍了scan method的原理,本文我们继续深入探究Join method的原理。
目前支持的join method list如下:
| Join method | NestLoop(table table[ table…]) | Forces nested loop for the joins on the tables specified. |
|---|---|---|
| HashJoin(table table[ table…]) | Forces hash join for the joins on the tables specified. | |
| MergeJoin(table table[ table…]) | Forces merge join for the joins on the tables specified. | |
| NoNestLoop(table table[ table…]) | Forces to not do nested loop for the joins on the tables specified. | |
| NoHashJoin(table table[ table…]) | Forces to not do hash join for the joins on the tables specified. | |
| NoMergeJoin(table table[ table…]) | Forces to not do merge join for the joins on the tables specified. |
主要是对NestLoop HashJoin MergeJoin三种join方式的控制。
原理
以MergeJoin(table table[ table…])为例:
在make_rel_from_joinlist时进入hook, set_join_config_options将hint指定的enable_mergejoin 置为on,并将其他scan method的startup_cost配置为disable_cost(即set NestLoop to off,set HashJoin to off) ,生成Mergejoin和Nestloop的joinpath, 最终计算最小代价确定joinpath为MergeJoin。

如图,sql默认走NestLoop,我们使用hint /*+ MergeJoin (du pu) */后走了MergeJoin。

debug关键过程做下验证:
首先set_join_config_options中:
enforce_mask=2 即set merge_join to on,set enable_nestloop to off,set enable_hashjoin to off
即Nestloop和Hashjoin的startup_cost为disable_cost

add_paths_to_joinrel :
mergejoin_allow总为true,为joinrel设置MergeJoin和Nestloop的path

enable_hashjoin为false,不涉及Hashjoin的path

由于Nestloop的startup_cost被设置为disable_cost,因此set_cheapest(rel)为T_MergePath

小结
本文深入分析了Join method的原理,其实就是对hint指定的几个表,将hint之外的join方式的startup_cost配置为disable_cost,这样最小代价就是hint指定的join方式了。




