- 生成连接路径时所使用的算法—动态规划和遗传,
- 动态规划推进到join_ search_one_ level
- 遗传算法推进到merge clump,
- 物理优化的部分从这两个函数开始就进入到了建立连接路径的阶段
-
连接路径指的是物理连接路径,也就是通过这种路径来实现逻辑连接操作
-
建立连接路径的过程就是不断地尝试生成这3种路径的过程。
- 相同的两个基表(Reloptlnfo)建立连接关系,
- 它们采用的物理路径不同,对应的路径的代价也就不同,
- 因此在建立连接路径的过程中,需不断尝试对路径筛选,
- 尽早地淘汰掉一些差路径
8.1检查
- 动规中需要将N-1层的每个Reloptlnfo和第1层的每个 Reloptlnfo尝试做连接,将连接产生的新的 Reloptlnfo保存到第N层,这个算法的时间复杂度是O(M*NM),M和N较大,它的解空间膨胀得快,影响搜索最优解的效率,
- 但在两个Reloptlnfo做尝试连接时,有些是明显不适合做连接操作的,可以通过检查的方式避开在这些Reloptlnfo间做连接操作,也就是说可以通过增加剪枝函数来避免无效搜索。
- SQL中会通过逻辑连接操作符和约束条件来指定两个表之间的逻辑连接关系,约束条件能起到过滤连接结果的作用,因此如果两个表上有约束条件,那么我们就可以尝试优
先对这两个表先做连接,这样就能保证有约束条件的表在查询计划的下层,也就是说能尽早地过滤数据,减少査询计划上层节点的计算量
- 两个表可能会有连接顺序的限制,
- SQL查询语句中指定 Lateral语义就能导致两个表的连接必须有先有后,建立物理连接路径的时候也必须考虑这种先后关系。
8.1.1初步检查
8.5建立连接路径
- add_paths_to_joinrel建立物理连接路径
- 虽然物理连接路径只有3种
- 但要同时考虑并行路径、参数化路径,
- 因此要考虑非常多
- 根据在待选的两个子Reloptlnfo中的路径生成新的父Reloptlnfo的路径的过程
- 创建扫描路径时,每个Reloptinfo中可能有多个扫描路径,
- 并行路径、参数化路径及普通的扫描路径
- 选哪个路径来生成新的父Reloptlnfo路径?
- 如图8-4
- sort_inner_and_outer主要生成Mergejoin
- 必须显式地对子Reloptlnfo排序
- 这时只需选择子Reloptlnfo中的总代价最低的路径(Reloptlnfo-> cheapest_total_path)
- match_unsorted_outer也生成Mergejoin,
- 但它只显式对内表排序,
- 只有外表的Pathkeys能匹配连接条件,
- 只需对内表排序就能获得MergeJoin路径,
- 这时内表的路径就不一定是总代价最低的路径,
- 如内表的路径是B树索引扫描路径,且它的Pathkeys满足当前连接条件,
- 那即使B树的索引扫描路径不是总代价最低的,但它可节省排序时间,
- 或许用它来产生连接路径的总代价反而最低
- 建立连接路径还要考虑参数化路径的生成,
- 参数化路径是参数的使用者,要保证参数的产生者还没有参与到连接路径的建立中,因此需要保存一个参数的产生者的表的集合( param source rels),在建立连接路径的过程中要检査,只有参数的产生者还没有参与到连接路径中时,当前连接才有效
- 为方便创建Mergejoin
- 需先对约束条件处理
- 把适用于Mergejoin的约束条件从中筛选(select_mergejoin_clauses),这样在sort_inner_and_outer函数和match_unsorted_outer中都可利用这个 Mergejoinable连接条件。
8.5.1 sort_inner_and_outer
- 显式对两个子Reloptlnfo排序
- 只考虑子Reloptlnfo中的cheapest_total_path
- 并行的Mergejoin的生成依赖
- 外表(LHS)的Reloptlnfo中是否有并行路径
- 建立并行的MergeJoin时选择的是子Reloptlnfo中代价最低的并行路径
- Mergejoin包含排序,那能尝试为它的连接结果生成一个Pathkeys?
- 它的连接结果的顺序和外表的顺序一致(排除Right Join和 Full Join,这两个都可能要在外表也就是LHS补NUL)
- 因此这个Pathkeys是可建立的
- add_paths_to_joinrel通过select_mergejoin_clauses获得适用于Mergejoin的约束条件,结合Mergejoin产生的Pathkeys的特点,约束条件的应用顺序就变得尤为重要
- 两个子约束条件A和B是Mergejoinable的约東
- 生成路径中可用{A,B}来生成一条Mergejoin
- 也可用{B,A}生成一条Mergejoin
- 这两个路径的估计代价相同
- 但这两条路径产生的连接结果的排序方式不同
- 也就是说两条路径产生的Pathkeys不同的
- 不同的Pathkeys对外层的操作产生不同影响
- TEST_A LEFT JOIN TEST_B ON TEST_A.a= TEST_B.a
- AND
- TEST_A.b=TEST_B.b
- 这部分如果要生成Mergejoin
- 则它的外表TEST_A排序顺序可{TEST A.a, TEST A.b}和{TEST A.b, TEST A.a}这两种Pathkeys
- TEST_A LEFT JOIN TEST_B的连接结果还要和TEST_C做 Fulljoin
- 在Fulin的约束条件中包含TEST A.b,
- TEST_A LEFT JOIN TEST_B选择{ TEST A.b, TEST A.a}作为 Mergejoin的 Pathkeys,
- Mergejoin的连接结果的第一排序键就是 TEST A.b,
- 和上层的 TEST_C做Mergejoin连接的时候就省略对TEST_A.b的排序
8.5.2 match_unsorted_outer
- sort_inner_and_outer生成显式排序的 Merge Join路径,因此它只选择了待连接的两个 Reloptlnfo中的代价最低的路径( cheapest total path,并行路径建立时则考虑了外表的最低
代价的并行路径)参与 Merge Join路径的生成,由于需要显式排序,因此最低启动代价的路径
没有什么用。
- match_unsorted_outer考虑那些外表已经有序的,对内表要显式排序
- 如外表是B树索引扫描
- 早期还存在 match_unsorted_inner,后被废
- add_paths_to_joinrel负责考虑过交换两个待连接的Reloptlnfo的顺序,这样同个Reloptlnfo在match_unsorted_outer中会各有一次机会做外表和内表,如果还有match unsorted inner函数生成的路径,就会和 match unsorted outer函数生成的路径重复
8.5.2.1路径生成流程
- 如果外表有序,无论Nestloopjoin还是Mergejoin
- 连接的结果也会和外表的顺序一致
- 所以match_unsorted_outer中,主要考虑生成Nestloopjoin和Mergejoin
- 对生成Mergejoin,sort_inner_and_outer中假定内外表都无序,必须显式地对两表排序
- 因此它是通过 MergeJoinable的连接条件来生成Pathkeys,然后不断调整Pathkeys中的 Pathkey的顺序来获得不同顺序的Pathkeys,然后再根据不同顺序的Pathkeys来决定内表的innerkeys和外表的outerkeys
- match_unsorted_ outer
- 假定外表路径有序,
- 它按照外表的Pathkeys反过来排序连接条件(外表的Pathkeys直接
就可以作为outerkeys用),査看连接条件中有哪些是和当前的 Pathkeys匹配的,把匹配的连接条件筛选出来(因为用的是外表的 Pathkeys,因此并不是所有的 Merge Joinable约束条件都可以用上),然后再参照匹配出来的连接条件生成内表需要显式排序的innerkeys,对比如图8-6