joinpath.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:16k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * joinpath.c
  4.  *   Routines to find all possible paths for processing a set of joins
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.38.2.1 1999/08/02 06:26:57 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include <sys/types.h>
  15. #include <math.h>
  16. #include "postgres.h"
  17. #include "optimizer/cost.h"
  18. #include "optimizer/pathnode.h"
  19. #include "optimizer/paths.h"
  20. static Path *best_innerjoin(List *join_paths, List *outer_relid);
  21. static List *sort_inner_and_outer(RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel,
  22.  List *mergeinfo_list);
  23. static List *match_unsorted_outer(RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel,
  24. List *outerpath_list, Path *cheapest_inner, Path *best_innerjoin,
  25.  List *mergeinfo_list);
  26. static List *match_unsorted_inner(RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel,
  27.  List *innerpath_list, List *mergeinfo_list);
  28. static List *hash_inner_and_outer(RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel,
  29.  List *hashinfo_list);
  30. /*
  31.  * update_rels_pathlist_for_joins
  32.  *   Creates all possible ways to process joins for each of the join
  33.  *   relations in the list 'joinrels.'  Each unique path will be included
  34.  *   in the join relation's 'pathlist' field.
  35.  *
  36.  *   In postgres, n-way joins are handled left-only(permuting clauseless
  37.  *   joins doesn't usually win much).
  38.  *
  39.  *   if BushyPlanFlag is true, bushy tree plans will be generated
  40.  *
  41.  * 'joinrels' is the list of relation entries to be joined
  42.  *
  43.  * Modifies the pathlist field of the appropriate rel node to contain
  44.  * the unique join paths.
  45.  * If bushy trees are considered, may modify the relid field of the
  46.  * join rel nodes to flatten the lists.
  47.  *
  48.  * It does a destructive modification.
  49.  */
  50. void
  51. update_rels_pathlist_for_joins(Query *root, List *joinrels)
  52. {
  53. List    *mergeinfo_list = NIL;
  54. List    *hashinfo_list = NIL;
  55. List    *j;
  56. foreach(j, joinrels)
  57. {
  58. RelOptInfo *joinrel = (RelOptInfo *) lfirst(j);
  59. Relids innerrelids;
  60. Relids outerrelids;
  61. RelOptInfo *innerrel;
  62. RelOptInfo *outerrel;
  63. Path    *bestinnerjoin;
  64. List    *pathlist = NIL;
  65. /* flatten out relids later in this function */
  66. outerrelids = lfirst(joinrel->relids);
  67. innerrelids = lsecond(joinrel->relids);
  68. /*
  69.  * base relation id is an integer and join relation relid is a
  70.  * list of integers.
  71.  */
  72. innerrel = (length(innerrelids) == 1) ?
  73. get_base_rel(root, lfirsti(innerrelids)) :
  74. get_join_rel(root, innerrelids);
  75. outerrel = (length(outerrelids) == 1) ?
  76. get_base_rel(root, lfirsti(outerrelids)) :
  77. get_join_rel(root, outerrelids);
  78. bestinnerjoin = best_innerjoin(innerrel->innerjoin, outerrel->relids);
  79. if (_enable_mergejoin_)
  80. mergeinfo_list = group_clauses_by_order(joinrel->restrictinfo,
  81. innerrel->relids);
  82. if (_enable_hashjoin_)
  83. hashinfo_list = group_clauses_by_hashop(joinrel->restrictinfo,
  84. innerrel->relids);
  85. /* need to flatten the relids list */
  86. joinrel->relids = nconc(listCopy(outerrelids),
  87. listCopy(innerrelids));
  88. /*
  89.  * 1. Consider mergejoin paths where both relations must be
  90.  * explicitly sorted.
  91.  */
  92. pathlist = sort_inner_and_outer(joinrel, outerrel,
  93. innerrel, mergeinfo_list);
  94. /*
  95.  * 2. Consider paths where the outer relation need not be
  96.  * explicitly sorted. This may include either nestloops and
  97.  * mergejoins where the outer path is already ordered.
  98.  */
  99. pathlist = add_pathlist(joinrel, pathlist,
  100. match_unsorted_outer(joinrel,
  101.  outerrel,
  102.  innerrel,
  103.  outerrel->pathlist,
  104.   innerrel->cheapestpath,
  105.  bestinnerjoin,
  106.  mergeinfo_list));
  107. /*
  108.  * 3. Consider paths where the inner relation need not be
  109.  * explicitly sorted.  This may include nestloops and mergejoins
  110.  * the actual nestloop nodes were constructed in
  111.  * (match_unsorted_outer).
  112.  */
  113. pathlist = add_pathlist(joinrel, pathlist,
  114. match_unsorted_inner(joinrel, outerrel,
  115.  innerrel,
  116.  innerrel->pathlist,
  117.  mergeinfo_list));
  118. /*
  119.  * 4. Consider paths where both outer and inner relations must be
  120.  * hashed before being joined.
  121.  */
  122. pathlist = add_pathlist(joinrel, pathlist,
  123. hash_inner_and_outer(joinrel, outerrel,
  124.    innerrel, hashinfo_list));
  125. joinrel->pathlist = pathlist;
  126. }
  127. }
  128. /*
  129.  * best_innerjoin
  130.  *   Find the cheapest index path that has already been identified by
  131.  *   (indexable_joinclauses) as being a possible inner path for the given
  132.  *   outer relation in a nestloop join.
  133.  *
  134.  * 'join_paths' is a list of join nodes
  135.  * 'outer_relid' is the relid of the outer join relation
  136.  *
  137.  * Returns the pathnode of the selected path.
  138.  */
  139. static Path *
  140. best_innerjoin(List *join_paths, Relids outer_relids)
  141. {
  142. Path    *cheapest = (Path *) NULL;
  143. List    *join_path;
  144. foreach(join_path, join_paths)
  145. {
  146. Path    *path = (Path *) lfirst(join_path);
  147. if (intMember(lfirsti(path->joinid), outer_relids) &&
  148. (cheapest == NULL ||
  149.  path_is_cheaper(path, cheapest)))
  150. cheapest = path;
  151. }
  152. return cheapest;
  153. }
  154. /*
  155.  * sort_inner_and_outer
  156.  *   Create mergejoin join paths by explicitly sorting both the outer and
  157.  *   inner join relations on each available merge ordering.
  158.  *
  159.  * 'joinrel' is the join relation
  160.  * 'outerrel' is the outer join relation
  161.  * 'innerrel' is the inner join relation
  162.  * 'mergeinfo_list' is a list of nodes containing info on(mergejoinable)
  163.  * clauses for joining the relations
  164.  *
  165.  * Returns a list of mergejoin paths.
  166.  */
  167. static List *
  168. sort_inner_and_outer(RelOptInfo *joinrel,
  169.  RelOptInfo *outerrel,
  170.  RelOptInfo *innerrel,
  171.  List *mergeinfo_list)
  172. {
  173. List    *ms_list = NIL;
  174. MergeInfo  *xmergeinfo = (MergeInfo *) NULL;
  175. MergePath  *temp_node = (MergePath *) NULL;
  176. List    *i;
  177. List    *outerkeys = NIL;
  178. List    *innerkeys = NIL;
  179. List    *merge_pathkeys = NIL;
  180. foreach(i, mergeinfo_list)
  181. {
  182. xmergeinfo = (MergeInfo *) lfirst(i);
  183. outerkeys = make_pathkeys_from_joinkeys(xmergeinfo->jmethod.jmkeys,
  184. outerrel->targetlist,
  185. OUTER);
  186. innerkeys = make_pathkeys_from_joinkeys(xmergeinfo->jmethod.jmkeys,
  187. innerrel->targetlist,
  188. INNER);
  189. merge_pathkeys = new_join_pathkeys(outerkeys, joinrel->targetlist,
  190.    xmergeinfo->jmethod.clauses);
  191. temp_node = create_mergejoin_path(joinrel,
  192.   outerrel->size,
  193.   innerrel->size,
  194.   outerrel->width,
  195.   innerrel->width,
  196.   (Path *) outerrel->cheapestpath,
  197.   (Path *) innerrel->cheapestpath,
  198.   merge_pathkeys,
  199.   xmergeinfo->m_ordering,
  200.   xmergeinfo->jmethod.clauses,
  201.   outerkeys,
  202.   innerkeys);
  203. ms_list = lappend(ms_list, temp_node);
  204. }
  205. return ms_list;
  206. }
  207. /*
  208.  * match_unsorted_outer
  209.  *   Creates possible join paths for processing a single join relation
  210.  *   'joinrel' by employing either iterative substitution or
  211.  *   mergejoining on each of its possible outer paths(assuming that the
  212.  *   outer relation need not be explicitly sorted).
  213.  *
  214.  *   1. The inner path is the cheapest available inner path.
  215.  *   2. Mergejoin wherever possible.  Mergejoin are considered if there
  216.  *  are mergejoinable join clauses between the outer and inner join
  217.  *  relations such that the outer path is keyed on the variables
  218.  *  appearing in the clauses. The corresponding inner merge path is
  219.  *  either a path whose keys match those of the outer path(if such a
  220.  *  path is available) or an explicit sort on the appropriate inner
  221.  *  join keys, whichever is cheaper.
  222.  *
  223.  * 'joinrel' is the join relation
  224.  * 'outerrel' is the outer join relation
  225.  * 'innerrel' is the inner join relation
  226.  * 'outerpath_list' is the list of possible outer paths
  227.  * 'cheapest_inner' is the cheapest inner path
  228.  * 'best_innerjoin' is the best inner index path(if any)
  229.  * 'mergeinfo_list' is a list of nodes containing info on mergejoinable
  230.  * clauses
  231.  *
  232.  * Returns a list of possible join path nodes.
  233.  */
  234. static List *
  235. match_unsorted_outer(RelOptInfo *joinrel,
  236.  RelOptInfo *outerrel,
  237.  RelOptInfo *innerrel,
  238.  List *outerpath_list,
  239.  Path *cheapest_inner,
  240.  Path *best_innerjoin,
  241.  List *mergeinfo_list)
  242. {
  243. Path    *outerpath = (Path *) NULL;
  244. List    *jp_list = NIL;
  245. List    *temp_node = NIL;
  246. List    *merge_pathkeys = NIL;
  247. Path    *nestinnerpath = (Path *) NULL;
  248. List    *paths = NIL;
  249. List    *i = NIL;
  250. PathOrder  *outerpath_ordering = NULL;
  251. foreach(i, outerpath_list)
  252. {
  253. List    *clauses = NIL;
  254. List    *matchedJoinKeys = NIL;
  255. List    *matchedJoinClauses = NIL;
  256. MergeInfo  *xmergeinfo = NULL;
  257. outerpath = (Path *) lfirst(i);
  258. outerpath_ordering = outerpath->pathorder;
  259. if (outerpath_ordering)
  260. xmergeinfo = match_order_mergeinfo(outerpath_ordering,
  261.    mergeinfo_list);
  262. if (xmergeinfo)
  263. clauses = xmergeinfo->jmethod.clauses;
  264. if (clauses)
  265. {
  266. List    *jmkeys = xmergeinfo->jmethod.jmkeys;
  267. order_joinkeys_by_pathkeys(outerpath->pathkeys,
  268.    jmkeys,
  269.    clauses,
  270.    OUTER,
  271.    &matchedJoinKeys,
  272.    &matchedJoinClauses);
  273. merge_pathkeys = new_join_pathkeys(outerpath->pathkeys,
  274.    joinrel->targetlist, clauses);
  275. }
  276. else
  277. merge_pathkeys = outerpath->pathkeys;
  278. if (best_innerjoin &&
  279. path_is_cheaper(best_innerjoin, cheapest_inner))
  280. nestinnerpath = best_innerjoin;
  281. else
  282. nestinnerpath = cheapest_inner;
  283. paths = lcons(create_nestloop_path(joinrel,
  284.    outerrel,
  285.    outerpath,
  286.    nestinnerpath,
  287.    merge_pathkeys),
  288.   NIL);
  289. if (clauses && matchedJoinKeys)
  290. {
  291. bool path_is_cheaper_than_sort;
  292. List    *varkeys = NIL;
  293. Path    *mergeinnerpath = get_cheapest_path_for_joinkeys(
  294.  matchedJoinKeys,
  295.   outerpath_ordering,
  296.   innerrel->pathlist,
  297.   INNER);
  298. /* Should we use the mergeinner, or sort the cheapest inner? */
  299. path_is_cheaper_than_sort = (bool) (mergeinnerpath &&
  300.  (mergeinnerpath->path_cost <
  301.   (cheapest_inner->path_cost +
  302.    cost_sort(matchedJoinKeys, innerrel->size,
  303.  innerrel->width))));
  304. if (!path_is_cheaper_than_sort)
  305. {
  306. varkeys = make_pathkeys_from_joinkeys(matchedJoinKeys,
  307. innerrel->targetlist,
  308.   INNER);
  309. }
  310. /*
  311.  * Keep track of the cost of the outer path used with this
  312.  * ordered inner path for later processing in
  313.  * (match_unsorted_inner), since it isn't a sort and thus
  314.  * wouldn't otherwise be considered.
  315.  */
  316. if (path_is_cheaper_than_sort)
  317. mergeinnerpath->outerjoincost = outerpath->path_cost;
  318. else
  319. mergeinnerpath = cheapest_inner;
  320. temp_node = lcons(create_mergejoin_path(joinrel,
  321. outerrel->size,
  322. innerrel->size,
  323. outerrel->width,
  324. innerrel->width,
  325. outerpath,
  326. mergeinnerpath,
  327. merge_pathkeys,
  328.   xmergeinfo->m_ordering,
  329. matchedJoinClauses,
  330. NIL,
  331. varkeys),
  332.   paths);
  333. }
  334. else
  335. temp_node = paths;
  336. jp_list = nconc(jp_list, temp_node);
  337. }
  338. return jp_list;
  339. }
  340. /*
  341.  * match_unsorted_inner
  342.  *   Find the cheapest ordered join path for a given(ordered, unsorted)
  343.  *   inner join path.
  344.  *
  345.  *   Scans through each path available on an inner join relation and tries
  346.  *   matching its ordering keys against those of mergejoin clauses.
  347.  *   If 1. an appropriately_ordered inner path and matching mergeclause are
  348.  * found, and
  349.  *  2. sorting the cheapest outer path is cheaper than using an ordered
  350.  *   but unsorted outer path(as was considered in
  351.  * (match_unsorted_outer)), then this merge path is considered.
  352.  *
  353.  * 'joinrel' is the join result relation
  354.  * 'outerrel' is the outer join relation
  355.  * 'innerrel' is the inner join relation
  356.  * 'innerpath_list' is the list of possible inner join paths
  357.  * 'mergeinfo_list' is a list of nodes containing info on mergejoinable
  358.  * clauses
  359.  *
  360.  * Returns a list of possible merge paths.
  361.  */
  362. static List *
  363. match_unsorted_inner(RelOptInfo *joinrel,
  364.  RelOptInfo *outerrel,
  365.  RelOptInfo *innerrel,
  366.  List *innerpath_list,
  367.  List *mergeinfo_list)
  368. {
  369. List    *mp_list = NIL;
  370. List    *i;
  371. foreach(i, innerpath_list)
  372. {
  373. Path    *innerpath = (Path *) lfirst(i);
  374. PathOrder  *innerpath_ordering = innerpath->pathorder;
  375. MergeInfo  *xmergeinfo = (MergeInfo *) NULL;
  376. List    *clauses = NIL;
  377. List    *matchedJoinKeys = NIL;
  378. List    *matchedJoinClauses = NIL;
  379. if (innerpath_ordering)
  380. xmergeinfo = match_order_mergeinfo(innerpath_ordering,
  381.    mergeinfo_list);
  382. if (xmergeinfo)
  383. clauses = ((JoinMethod *) xmergeinfo)->clauses;
  384. if (clauses)
  385. {
  386. List    *jmkeys = xmergeinfo->jmethod.jmkeys;
  387. order_joinkeys_by_pathkeys(innerpath->pathkeys,
  388.    jmkeys,
  389.    clauses,
  390.    INNER,
  391.    &matchedJoinKeys,
  392.    &matchedJoinClauses);
  393. }
  394. /*
  395.  * (match_unsorted_outer) if it is applicable. 'OuterJoinCost was
  396.  * set above in
  397.  */
  398. if (clauses && matchedJoinKeys)
  399. {
  400. Cost temp1;
  401. temp1 = outerrel->cheapestpath->path_cost +
  402. cost_sort(matchedJoinKeys, outerrel->size, outerrel->width);
  403. if (innerpath->outerjoincost <= 0 /* unset? */
  404. || innerpath->outerjoincost > temp1)
  405. {
  406. List    *outerkeys = make_pathkeys_from_joinkeys(matchedJoinKeys,
  407. outerrel->targetlist,
  408.   OUTER);
  409. List    *merge_pathkeys = new_join_pathkeys(outerkeys,
  410.  joinrel->targetlist,
  411.    clauses);
  412. mp_list = lappend(mp_list,
  413.   create_mergejoin_path(joinrel,
  414. outerrel->size,
  415. innerrel->size,
  416. outerrel->width,
  417. innerrel->width,
  418.  (Path *) outerrel->cheapestpath,
  419. innerpath,
  420. merge_pathkeys,
  421.   xmergeinfo->m_ordering,
  422.   matchedJoinClauses,
  423. outerkeys,
  424. NIL));
  425. }
  426. }
  427. }
  428. return mp_list;
  429. }
  430. /*
  431.  * hash_inner_and_outer-- XXX HASH
  432.  *   Create hashjoin join paths by explicitly hashing both the outer and
  433.  *   inner join relations on each available hash op.
  434.  *
  435.  * 'joinrel' is the join relation
  436.  * 'outerrel' is the outer join relation
  437.  * 'innerrel' is the inner join relation
  438.  * 'hashinfo_list' is a list of nodes containing info on(hashjoinable)
  439.  * clauses for joining the relations
  440.  *
  441.  * Returns a list of hashjoin paths.
  442.  */
  443. static List *
  444. hash_inner_and_outer(RelOptInfo *joinrel,
  445.  RelOptInfo *outerrel,
  446.  RelOptInfo *innerrel,
  447.  List *hashinfo_list)
  448. {
  449. List    *hjoin_list = NIL;
  450. List    *i;
  451. foreach(i, hashinfo_list)
  452. {
  453. HashInfo   *xhashinfo = (HashInfo *) lfirst(i);
  454. List    *outerkeys;
  455. List    *innerkeys;
  456. List    *hash_pathkeys;
  457. HashPath   *temp_node;
  458. outerkeys = make_pathkeys_from_joinkeys(
  459.   ((JoinMethod *) xhashinfo)->jmkeys,
  460. outerrel->targetlist,
  461. OUTER);
  462. innerkeys = make_pathkeys_from_joinkeys(
  463.   ((JoinMethod *) xhashinfo)->jmkeys,
  464. innerrel->targetlist,
  465. INNER);
  466. /*
  467.  * We cannot assume that the output of the hashjoin appears in any
  468.  * particular order, so it should have NIL pathkeys.
  469.  */
  470. #ifdef NOT_USED
  471. hash_pathkeys = new_join_pathkeys(outerkeys,
  472.   joinrel->targetlist,
  473. ((JoinMethod *) xhashinfo)->clauses);
  474. #else
  475. hash_pathkeys = NIL;
  476. #endif
  477. temp_node = create_hashjoin_path(joinrel,
  478.  outerrel->size,
  479.  innerrel->size,
  480.  outerrel->width,
  481.  innerrel->width,
  482.  (Path *) outerrel->cheapestpath,
  483.  (Path *) innerrel->cheapestpath,
  484.  hash_pathkeys,
  485.  xhashinfo->hashop,
  486.  ((JoinMethod *) xhashinfo)->clauses,
  487.  outerkeys,
  488.  innerkeys);
  489. hjoin_list = lappend(hjoin_list, temp_node);
  490. }
  491. return hjoin_list;
  492. }