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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * joinrels.c
  4.  *   Routines to determine which relations should be joined
  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/joinrels.c,v 1.35.2.1 1999/08/02 06:26:58 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "postgres.h"
  15. #include "optimizer/cost.h"
  16. #include "optimizer/joininfo.h"
  17. #include "optimizer/pathnode.h"
  18. #include "optimizer/paths.h"
  19. #include "optimizer/tlist.h"
  20. static List *new_joininfo_list(List *joininfo_list, Relids join_relids);
  21. static bool nonoverlap_sets(List *s1, List *s2);
  22. static bool is_subset(List *s1, List *s2);
  23. static void set_joinrel_size(RelOptInfo *joinrel, RelOptInfo *outer_rel,
  24.  RelOptInfo *inner_rel, JoinInfo *jinfo);
  25. static RelOptInfo *make_join_rel(RelOptInfo *outer_rel, RelOptInfo *inner_rel,
  26.  JoinInfo *joininfo);
  27. static List *new_join_tlist(List *tlist, int first_resdomno);
  28. /*
  29.  * make_rels_by_joins
  30.  *   Find all possible joins for each of the outer join relations in
  31.  *   'outer_rels'.  A rel node is created for each possible join relation,
  32.  *   and the resulting list of nodes is returned. If at all possible, only
  33.  *   those relations for which join clauses exist are considered. If none
  34.  *   of these exist for a given relation, all remaining possibilities are
  35.  *   considered.
  36.  *
  37.  * Returns a list of rel nodes corresponding to the new join relations.
  38.  */
  39. List *
  40. make_rels_by_joins(Query *root, List *old_rels)
  41. {
  42. List    *joined_rels = NIL;
  43. List    *join_list = NIL;
  44. List    *r = NIL;
  45. foreach(r, old_rels)
  46. {
  47. RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
  48. if (!(joined_rels = make_rels_by_clause_joins(root, old_rel,
  49.   old_rel->joininfo,
  50.   NIL)))
  51. {
  52. /*
  53.  * Oops, we have a relation that is not joined to any other
  54.  * relation.  Cartesian product time.
  55.  */
  56. joined_rels = make_rels_by_clauseless_joins(old_rel,
  57. root->base_rel_list);
  58. joined_rels = nconc(joined_rels,
  59. make_rels_by_clauseless_joins(old_rel,
  60.   old_rels));
  61. }
  62. join_list = nconc(join_list, joined_rels);
  63. }
  64. return join_list;
  65. }
  66. /*
  67.  * make_rels_by_clause_joins
  68.  *   Determines whether joins can be performed between an outer relation
  69.  *   'outer_rel' and those relations within 'outer_rel's joininfo nodes
  70.  *   (i.e., relations that participate in join clauses that 'outer_rel'
  71.  *   participates in).  This is possible if all but one of the relations
  72.  *   contained within the join clauses of the joininfo node are already
  73.  *   contained within 'outer_rel'.
  74.  *
  75.  * 'outer_rel' is the relation entry for the outer relation
  76.  * 'joininfo_list' is a list of join clauses which 'outer_rel'
  77.  * participates in
  78.  *
  79.  * Returns a list of new join relations.
  80.  */
  81. List *
  82. make_rels_by_clause_joins(Query *root, RelOptInfo *old_rel,
  83.   List *joininfo_list, Relids only_relids)
  84. {
  85. List    *join_list = NIL;
  86. List    *i = NIL;
  87. foreach(i, joininfo_list)
  88. {
  89. JoinInfo   *joininfo = (JoinInfo *) lfirst(i);
  90. RelOptInfo *joined_rel;
  91. Relids unjoined_relids = joininfo->unjoined_relids;
  92. if (unjoined_relids != NIL)
  93. {
  94. if (length(unjoined_relids) == 1 &&
  95. (only_relids == NIL ||
  96. /* geqo only wants certain relids to make new rels */
  97.  intMember(lfirsti(unjoined_relids), only_relids)))
  98. {
  99. joined_rel = make_join_rel(old_rel,
  100.    get_base_rel(root,
  101.    lfirsti(unjoined_relids)),
  102.    joininfo);
  103. join_list = lappend(join_list, joined_rel);
  104. /* Right-sided plan */
  105. if (length(old_rel->relids) > 1)
  106. {
  107. joined_rel = make_join_rel(
  108. get_base_rel(root, lfirsti(unjoined_relids)),
  109.    old_rel,
  110.    joininfo);
  111. join_list = lappend(join_list, joined_rel);
  112. }
  113. }
  114. if (only_relids == NIL) /* no bushy from geqo */
  115. {
  116. List    *r;
  117. foreach(r, root->join_rel_list)
  118. {
  119. RelOptInfo *join_rel = lfirst(r);
  120. Assert(length(join_rel->relids) > 1);
  121. if (is_subset(unjoined_relids, join_rel->relids) &&
  122.   nonoverlap_sets(old_rel->relids, join_rel->relids))
  123. {
  124. joined_rel = make_join_rel(old_rel,
  125.    join_rel,
  126.    joininfo);
  127. join_list = lappend(join_list, joined_rel);
  128. }
  129. }
  130. }
  131. }
  132. }
  133. return join_list;
  134. }
  135. /*
  136.  * make_rels_by_clauseless_joins
  137.  *   Given an outer relation 'outer_rel' and a list of inner relations
  138.  *   'inner_rels', create a join relation between 'outer_rel' and each
  139.  *   member of 'inner_rels' that isn't already included in 'outer_rel'.
  140.  *
  141.  * Returns a list of new join relations.
  142.  */
  143. List *
  144. make_rels_by_clauseless_joins(RelOptInfo *old_rel, List *inner_rels)
  145. {
  146. RelOptInfo *inner_rel;
  147. List    *t_list = NIL;
  148. List    *i = NIL;
  149. foreach(i, inner_rels)
  150. {
  151. inner_rel = (RelOptInfo *) lfirst(i);
  152. if (nonoverlap_sets(inner_rel->relids, old_rel->relids))
  153. {
  154. t_list = lappend(t_list,
  155.  make_join_rel(old_rel,
  156.    inner_rel,
  157.    (JoinInfo *) NULL));
  158. }
  159. }
  160. return t_list;
  161. }
  162. /*
  163.  * make_join_rel
  164.  *   Creates and initializes a new join relation.
  165.  *
  166.  * 'outer_rel' and 'inner_rel' are relation nodes for the relations to be
  167.  * joined
  168.  * 'joininfo' is the joininfo node(join clause) containing both
  169.  * 'outer_rel' and 'inner_rel', if any exists
  170.  *
  171.  * Returns the new join relation node.
  172.  */
  173. static RelOptInfo *
  174. make_join_rel(RelOptInfo *outer_rel, RelOptInfo *inner_rel, JoinInfo *joininfo)
  175. {
  176. RelOptInfo *joinrel = makeNode(RelOptInfo);
  177. List    *joinrel_joininfo_list = NIL;
  178. List    *new_outer_tlist;
  179. List    *new_inner_tlist;
  180. /*
  181.  * Create a new tlist by removing irrelevant elements from both tlists
  182.  * of the outer and inner join relations and then merging the results
  183.  * together.
  184.  */
  185. new_outer_tlist = new_join_tlist(outer_rel->targetlist, 1);
  186. new_inner_tlist = new_join_tlist(inner_rel->targetlist,
  187.  length(new_outer_tlist) + 1);
  188. joinrel->relids = NIL;
  189. joinrel->indexed = false;
  190. joinrel->pages = 0;
  191. joinrel->tuples = 0;
  192. joinrel->width = 0;
  193. /* joinrel->targetlist = NIL;*/
  194. joinrel->pathlist = NIL;
  195. joinrel->cheapestpath = (Path *) NULL;
  196. joinrel->pruneable = true;
  197. joinrel->classlist = NULL;
  198. joinrel->relam = InvalidOid;
  199. joinrel->ordering = NULL;
  200. joinrel->restrictinfo = NIL;
  201. joinrel->joininfo = NULL;
  202. joinrel->innerjoin = NIL;
  203. /*
  204.  * This function uses a trick to pass inner/outer rels as different
  205.  * lists, and then flattens it out later.  bjm
  206.  */
  207. joinrel->relids = lcons(outer_rel->relids, lcons(inner_rel->relids, NIL));
  208. new_outer_tlist = nconc(new_outer_tlist, new_inner_tlist);
  209. joinrel->targetlist = new_outer_tlist;
  210. if (joininfo)
  211. joinrel->restrictinfo = joininfo->jinfo_restrictinfo;
  212. joinrel_joininfo_list = new_joininfo_list(
  213.    nconc(copyObject(outer_rel->joininfo),
  214.  copyObject(inner_rel->joininfo)),
  215.    nconc(listCopy(outer_rel->relids),
  216.    listCopy(inner_rel->relids)));
  217. joinrel->joininfo = joinrel_joininfo_list;
  218. set_joinrel_size(joinrel, outer_rel, inner_rel, joininfo);
  219. return joinrel;
  220. }
  221. /*
  222.  * new_join_tlist
  223.  *   Builds a join relations's target list by keeping those elements that
  224.  *   will be in the final target list and any other elements that are still
  225.  *   needed for future joins. For a target list entry to still be needed
  226.  *   for future joins, its 'joinlist' field must not be empty after removal
  227.  *   of all relids in 'other_relids'.
  228.  *
  229.  * 'tlist' is the target list of one of the join relations
  230.  * 'other_relids' is a list of relids contained within the other
  231.  * join relation
  232.  * 'first_resdomno' is the resdom number to use for the first created
  233.  * target list entry
  234.  *
  235.  * Returns the new target list.
  236.  */
  237. static List *
  238. new_join_tlist(List *tlist,
  239.    int first_resdomno)
  240. {
  241. int resdomno = first_resdomno - 1;
  242. TargetEntry *xtl = NULL;
  243. List    *t_list = NIL;
  244. List    *i = NIL;
  245. List    *join_list = NIL;
  246. bool in_final_tlist = false;
  247. foreach(i, tlist)
  248. {
  249. xtl = lfirst(i);
  250. /*
  251.  * XXX surely this is wrong?  join_list is never changed?  tgl
  252.  * 2/99
  253.  */
  254. in_final_tlist = (join_list == NIL);
  255. if (in_final_tlist)
  256. {
  257. resdomno += 1;
  258. t_list = lappend(t_list, create_tl_element(get_expr(xtl), resdomno));
  259. }
  260. }
  261. return t_list;
  262. }
  263. /*
  264.  * new_joininfo_list
  265.  *   Builds a join relation's joininfo list by checking for join clauses
  266.  *   which still need to used in future joins involving this relation.  A
  267.  *   join clause is still needed if there are still relations in the clause
  268.  *   not contained in the list of relations comprising this join relation.
  269.  *   New joininfo nodes are only created and added to
  270.  *   'current_joininfo_list' if a node for a particular join hasn't already
  271.  *   been created.
  272.  *
  273.  * 'current_joininfo_list' contains a list of those joininfo nodes that
  274.  * have already been built
  275.  * 'joininfo_list' is the list of join clauses involving this relation
  276.  * 'join_relids' is a list of relids corresponding to the relations
  277.  * currently being joined
  278.  *
  279.  * Returns a list of joininfo nodes, new and old.
  280.  */
  281. static List *
  282. new_joininfo_list(List *joininfo_list, Relids join_relids)
  283. {
  284. List    *current_joininfo_list = NIL;
  285. Relids new_unjoined_relids = NIL;
  286. JoinInfo   *other_joininfo = (JoinInfo *) NULL;
  287. List    *xjoininfo = NIL;
  288. foreach(xjoininfo, joininfo_list)
  289. {
  290. List    *or;
  291. JoinInfo   *joininfo = (JoinInfo *) lfirst(xjoininfo);
  292. new_unjoined_relids = joininfo->unjoined_relids;
  293. foreach(or, new_unjoined_relids)
  294. {
  295. if (intMember(lfirsti(or), join_relids))
  296. new_unjoined_relids = lremove((void *) lfirst(or), new_unjoined_relids);
  297. }
  298. joininfo->unjoined_relids = new_unjoined_relids;
  299. if (new_unjoined_relids != NIL)
  300. {
  301. other_joininfo = joininfo_member(new_unjoined_relids,
  302.  current_joininfo_list);
  303. if (other_joininfo)
  304. {
  305. other_joininfo->jinfo_restrictinfo = (List *)
  306. LispUnion(joininfo->jinfo_restrictinfo,
  307.   other_joininfo->jinfo_restrictinfo);
  308. }
  309. else
  310. {
  311. other_joininfo = makeNode(JoinInfo);
  312. other_joininfo->unjoined_relids = joininfo->unjoined_relids;
  313. other_joininfo->jinfo_restrictinfo = joininfo->jinfo_restrictinfo;
  314. other_joininfo->mergejoinable = joininfo->mergejoinable;
  315. other_joininfo->hashjoinable = joininfo->hashjoinable;
  316. current_joininfo_list = lcons(other_joininfo,
  317.   current_joininfo_list);
  318. }
  319. }
  320. }
  321. return current_joininfo_list;
  322. }
  323. /*
  324.  * get_cheapest_complete_rel
  325.  *    Find the join relation that includes all the original
  326.  *    relations, i.e. the final join result.
  327.  *
  328.  * 'join_rel_list' is a list of join relations.
  329.  *
  330.  * Returns the list of final join relations.
  331.  */
  332. RelOptInfo *
  333. get_cheapest_complete_rel(List *join_rel_list)
  334. {
  335. List    *xrel = NIL;
  336. RelOptInfo *final_rel = NULL;
  337. /*
  338.  * find the relations that have no further joins, i.e., its joininfos
  339.  * all have unjoined_relids nil.
  340.  */
  341. foreach(xrel, join_rel_list)
  342. {
  343. RelOptInfo *rel = (RelOptInfo *) lfirst(xrel);
  344. List    *xjoininfo = NIL;
  345. bool final = true;
  346. foreach(xjoininfo, rel->joininfo)
  347. {
  348. JoinInfo   *joininfo = (JoinInfo *) lfirst(xjoininfo);
  349. if (joininfo->unjoined_relids != NIL)
  350. {
  351. final = false;
  352. break;
  353. }
  354. }
  355. if (final)
  356. if (final_rel == NULL ||
  357.  path_is_cheaper(rel->cheapestpath, final_rel->cheapestpath))
  358. final_rel = rel;
  359. }
  360. return final_rel;
  361. }
  362. static bool
  363. nonoverlap_sets(List *s1, List *s2)
  364. {
  365. List    *x = NIL;
  366. foreach(x, s1)
  367. {
  368. int e = lfirsti(x);
  369. if (intMember(e, s2))
  370. return false;
  371. }
  372. return true;
  373. }
  374. static bool
  375. is_subset(List *s1, List *s2)
  376. {
  377. List    *x = NIL;
  378. foreach(x, s1)
  379. {
  380. int e = lfirsti(x);
  381. if (!intMember(e, s2))
  382. return false;
  383. }
  384. return true;
  385. }
  386. static void
  387. set_joinrel_size(RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, JoinInfo *jinfo)
  388. {
  389. int ntuples;
  390. float selec;
  391. /*
  392.  * voodoo magic. but better than a size of 0. I have no idea why we
  393.  * didn't set the size before. -ay 2/95
  394.  */
  395. if (jinfo == NULL)
  396. {
  397. /* worst case: the cartesian product */
  398. ntuples = outer_rel->tuples * inner_rel->tuples;
  399. }
  400. else
  401. {
  402. selec = product_selec(jinfo->jinfo_restrictinfo);
  403. /* ntuples = Min(outer_rel->tuples,inner_rel->tuples) * selec; */
  404. ntuples = outer_rel->tuples * inner_rel->tuples * selec;
  405. }
  406. /*
  407.  * I bet sizes less than 1 will screw up optimization so make the best
  408.  * case 1 instead of 0 - jolly
  409.  */
  410. if (ntuples < 1)
  411. ntuples = 1;
  412. joinrel->tuples = ntuples;
  413. }