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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * clausesel.c
  4.  *   Routines to compute and set clause selectivities
  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/clausesel.c,v 1.20.2.1 1999/08/02 06:26:57 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "postgres.h"
  15. #include "catalog/pg_operator.h"
  16. #include "optimizer/clauses.h"
  17. #include "optimizer/cost.h"
  18. #include "optimizer/internal.h"
  19. #include "optimizer/plancat.h" 
  20. #include "optimizer/restrictinfo.h"
  21. #include "parser/parsetree.h" 
  22. #include "utils/lsyscache.h"
  23. static Cost compute_selec(Query *root, List *clauses, List *or_selectivities);
  24. /****************************************************************************
  25.  * ROUTINES TO SET CLAUSE SELECTIVITIES
  26.  ****************************************************************************/
  27. /*
  28.  * set_clause_selectivities -
  29.  *   Sets the selectivity field for each of clause in 'restrictinfo-list'
  30.  *   to 'new-selectivity'.  If the selectivity has already been set, reset
  31.  *   it only if the new one is better.
  32.  *
  33.  * Returns nothing of interest.
  34.  *
  35.  */
  36. void
  37. set_clause_selectivities(List *restrictinfo_list, Cost new_selectivity)
  38. {
  39. List    *temp;
  40. RestrictInfo *clausenode;
  41. Cost cost_clause;
  42. foreach(temp, restrictinfo_list)
  43. {
  44. clausenode = (RestrictInfo *) lfirst(temp);
  45. cost_clause = clausenode->selectivity;
  46. if (cost_clause <= 0 || new_selectivity < cost_clause)
  47. clausenode->selectivity = new_selectivity;
  48. }
  49. }
  50. /*
  51.  * product_selec -
  52.  *   Multiplies the selectivities of each clause in 'restrictinfo-list'.
  53.  *
  54.  * Returns a flonum corresponding to the selectivity of 'restrictinfo-list'.
  55.  */
  56. Cost
  57. product_selec(List *restrictinfo_list)
  58. {
  59. Cost result = 1.0;
  60. if (restrictinfo_list != NIL)
  61. {
  62. List    *xclausenode = NIL;
  63. Cost temp;
  64. foreach(xclausenode, restrictinfo_list)
  65. {
  66. temp = ((RestrictInfo *) lfirst(xclausenode))->selectivity;
  67. result = result * temp;
  68. }
  69. }
  70. return result;
  71. }
  72. /*
  73.  * set_rest_relselec -
  74.  *   Scans through clauses on each relation and assigns a selectivity to
  75.  *   those clauses that haven't been assigned a selectivity by an index.
  76.  *
  77.  * Returns nothing of interest.
  78.  * MODIFIES: selectivities of the various rel's restrictinfo
  79.  *   slots.
  80.  */
  81. void
  82. set_rest_relselec(Query *root, List *rel_list)
  83. {
  84. RelOptInfo *rel;
  85. List    *x;
  86. foreach(x, rel_list)
  87. {
  88. rel = (RelOptInfo *) lfirst(x);
  89. set_rest_selec(root, rel->restrictinfo);
  90. }
  91. }
  92. /*
  93.  * set_rest_selec -
  94.  *   Sets the selectivity fields for those clauses within a single
  95.  *   relation's 'restrictinfo-list' that haven't already been set.
  96.  *
  97.  * Returns nothing of interest.
  98.  *
  99.  */
  100. void
  101. set_rest_selec(Query *root, List *restrictinfo_list)
  102. {
  103. List    *temp = NIL;
  104. RestrictInfo *clausenode = (RestrictInfo *) NULL;
  105. Cost cost_clause;
  106. foreach(temp, restrictinfo_list)
  107. {
  108. clausenode = (RestrictInfo *) lfirst(temp);
  109. cost_clause = clausenode->selectivity;
  110. /*
  111.  * Check to see if the selectivity of this clause or any 'or'
  112.  * subclauses (if any) haven't been set yet.
  113.  */
  114. if (cost_clause <= 0 || valid_or_clause(clausenode))
  115. {
  116. clausenode->selectivity = compute_clause_selec(root,
  117.  (Node *) clausenode->clause,
  118.  lcons(makeFloat(cost_clause), NIL));
  119. }
  120. }
  121. }
  122. /****************************************************************************
  123.  * ROUTINES TO COMPUTE SELECTIVITIES
  124.  ****************************************************************************/
  125. /*
  126.  * compute_clause_selec -
  127.  *   Given a clause, this routine will compute the selectivity of the
  128.  *   clause by calling 'compute_selec' with the appropriate parameters
  129.  *   and possibly use that return value to compute the real selectivity
  130.  *   of a clause.
  131.  *
  132.  * 'or-selectivities' are selectivities that have already been assigned
  133.  * to subclauses of an 'or' clause.
  134.  *
  135.  * Returns a flonum corresponding to the clause selectivity.
  136.  *
  137.  */
  138. Cost
  139. compute_clause_selec(Query *root, Node *clause, List *or_selectivities)
  140. {
  141. if (is_opclause(clause))
  142. return compute_selec(root, lcons(clause, NIL), or_selectivities);
  143. else if (not_clause(clause))
  144. {
  145. /*
  146.  * 'not' gets "1.0 - selectivity-of-inner-clause".
  147.  */
  148. return (1.000000 - compute_selec(root,
  149.  lcons(get_notclausearg((Expr *) clause),
  150.    NIL),
  151.  or_selectivities));
  152. }
  153. else if (or_clause(clause))
  154. {
  155. /*
  156.  * Both 'or' and 'and' clauses are evaluated as described in
  157.  * (compute_selec).
  158.  */
  159. return compute_selec(root, ((Expr *) clause)->args, or_selectivities);
  160. }
  161. else
  162. return compute_selec(root, lcons(clause, NIL), or_selectivities);
  163. }
  164. /*
  165.  * compute_selec -
  166.  *   Computes the selectivity of a clause.
  167.  *
  168.  *   If there is more than one clause in the argument 'clauses', then the
  169.  *   desired selectivity is that of an 'or' clause.  Selectivities for an
  170.  *   'or' clause such as (OR a b) are computed by finding the selectivity
  171.  *   of a (s1) and b (s2) and computing s1+s2 - s1*s2.
  172.  *
  173.  *   In addition, if the clause is an 'or' clause, individual selectivities
  174.  *   may have already been assigned by indices to subclauses. These values
  175.  *   are contained in the list 'or-selectivities'.
  176.  *
  177.  * Returns the clause selectivity as a flonum.
  178.  *
  179.  */
  180. static Cost
  181. compute_selec(Query *root, List *clauses, List *or_selectivities)
  182. {
  183. Cost s1 = 0;
  184. List    *clause = lfirst(clauses);
  185. if (clause == NULL)
  186. s1 = 1.0;
  187. else if (IsA(clause, Param))
  188. {
  189. /* XXX How're we handling this before?? -ay */
  190. s1 = 1.0;
  191. }
  192. else if (IsA(clause, Const))
  193. s1 = ((bool) ((Const *) clause)->constvalue) ? 1.0 : 0.0;
  194. else if (IsA(clause, Var))
  195. {
  196. Oid relid = getrelid(((Var *) clause)->varno,
  197.  root->rtable);
  198. /*
  199.  * we have a bool Var. This is exactly equivalent to the clause:
  200.  * reln.attribute = 't' so we compute the selectivity as if that
  201.  * is what we have. The magic #define constants are a hack.  I
  202.  * didn't want to have to do system cache look ups to find out all
  203.  * of that info.
  204.  */
  205. s1 = restriction_selectivity(F_EQSEL,
  206.  BooleanEqualOperator,
  207.  relid,
  208.  ((Var *) clause)->varoattno,
  209.  "t",
  210.  _SELEC_CONSTANT_RIGHT_);
  211. }
  212. else if (or_selectivities)
  213. {
  214. /* If s1 has already been assigned by an index, use that value. */
  215. List    *this_sel = lfirst(or_selectivities);
  216. s1 = floatVal(this_sel);
  217. }
  218. else if (is_funcclause((Node *) clause))
  219. {
  220. /* this isn't an Oper, it's a Func!! */
  221. /*
  222.  * This is not an operator, so we guess at the selectivity. THIS
  223.  * IS A HACK TO GET V4 OUT THE DOOR.  FUNCS SHOULD BE ABLE TO HAVE
  224.  * SELECTIVITIES THEMSELVES.    -- JMH 7/9/92
  225.  */
  226. s1 = 0.1;
  227. }
  228. else if (not_clause((Node *) clause))
  229. {
  230. /* negate this baby */
  231. return 1 - compute_selec(root, ((Expr *) clause)->args, or_selectivities);
  232. }
  233. else if (is_subplan((Node *) clause))
  234. {
  235. /*
  236.  * Just for the moment! FIX ME! - vadim 02/04/98
  237.  */
  238. s1 = 1.0;
  239. }
  240. else if (NumRelids((Node *) clause) == 1)
  241. {
  242. /*
  243.  * ...otherwise, calculate s1 from 'clauses'. The clause is not a
  244.  * join clause, since there is only one relid in the clause.  The
  245.  * clause selectivity will be based on the operator selectivity
  246.  * and operand values.
  247.  */
  248. Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
  249. RegProcedure oprrest = get_oprrest(opno);
  250. Oid relid;
  251. int relidx;
  252. AttrNumber attno;
  253. Datum constval;
  254. int flag;
  255. get_relattval((Node *) clause, &relidx, &attno, &constval, &flag);
  256. relid = getrelid(relidx, root->rtable);
  257. /*
  258.  * if the oprrest procedure is missing for whatever reason, use a
  259.  * selectivity of 0.5
  260.  */
  261. if (!oprrest)
  262. s1 = (Cost) (0.5);
  263. else if (attno == InvalidAttrNumber)
  264. {
  265. /*
  266.  * attno can be Invalid if the clause had a function in it,
  267.  * i.e.   WHERE myFunc(f) = 10
  268.  */
  269. /* this should be FIXED somehow to use function selectivity */
  270. s1 = (Cost) (0.5);
  271. }
  272. else
  273. s1 = (Cost) restriction_selectivity(oprrest,
  274. opno,
  275. relid,
  276. attno,
  277. (char *) constval,
  278. flag);
  279. }
  280. else
  281. {
  282. /*
  283.  * The clause must be a join clause.  The clause selectivity will
  284.  * be based on the relations to be scanned and the attributes they
  285.  * are to be joined on.
  286.  */
  287. Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
  288. RegProcedure oprjoin = get_oprjoin(opno);
  289. int relid1,
  290. relid2;
  291. AttrNumber attno1,
  292. attno2;
  293. get_rels_atts((Node *) clause, &relid1, &attno1, &relid2, &attno2);
  294. relid1 = getrelid(relid1, root->rtable);
  295. relid2 = getrelid(relid2, root->rtable);
  296. /*
  297.  * if the oprjoin procedure is missing for whatever reason, use a
  298.  * selectivity of 0.5
  299.  */
  300. if (!oprjoin)
  301. s1 = (Cost) (0.5);
  302. else
  303. s1 = (Cost) join_selectivity(oprjoin,
  304.  opno,
  305.  relid1,
  306.  attno1,
  307.  relid2,
  308.  attno2);
  309. }
  310. /*
  311.  * A null clause list eliminates no tuples, so return a selectivity of
  312.  * 1.0.  If there is only one clause, the selectivity is not that of
  313.  * an 'or' clause, but rather that of the single clause.
  314.  */
  315. if (lnext(clauses) == NIL)
  316. return s1;
  317. else
  318. {
  319. /* Compute selectivity of the 'or'ed subclauses. */
  320. /* Added check for taking lnext(NIL).  -- JMH 3/9/92 */
  321. Cost s2;
  322. if (or_selectivities != NIL)
  323. s2 = compute_selec(root, lnext(clauses), lnext(or_selectivities));
  324. else
  325. s2 = compute_selec(root, lnext(clauses), NIL);
  326. return s1 + s2 - s1 * s2;
  327. }
  328. }