X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=make_join_rel.c;h=94bbfb8a84db95f0d2a49449b99695804d4b5c5b;hb=2a9e14e50905decc0d37506284fbfb5bf1e094ac;hp=c05824655b3c9ea92731260a405784d50f8ece4e;hpb=67fc7f82e64c094808a05740cb9c55c0f121c1c6;p=pghintplan%2Fpg_hint_plan.git diff --git a/make_join_rel.c b/make_join_rel.c index c058246..94bbfb8 100644 --- a/make_join_rel.c +++ b/make_join_rel.c @@ -1,18 +1,50 @@ /*------------------------------------------------------------------------- * * make_join_rel.c - * Routines copied from PostgreSQL core distribution. + * Routines copied from PostgreSQL core distribution with some + * modifications. * * src/backend/optimizer/path/joinrels.c * make_join_rel() * - * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group + * Portions Copyright (c) 2013-2017, NIPPON TELEGRAPH AND TELEPHONE CORPORATION + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *------------------------------------------------------------------------- */ /* + * adjust_rows: tweak estimated row numbers according to the hint. +*/ +static double +adjust_rows(double rows, RowsHint *hint) +{ + double result = 0.0; /* keep compiler quiet */ + + if (hint->value_type == RVT_ABSOLUTE) + result = hint->rows; + else if (hint->value_type == RVT_ADD) + result = rows + hint->rows; + else if (hint->value_type == RVT_SUB) + result = rows - hint->rows; + else if (hint->value_type == RVT_MULTI) + result = rows * hint->rows; + else + Assert(false); /* unrecognized rows value type */ + + hint->base.state = HINT_STATE_USED; + if (result < 1.0) + ereport(WARNING, + (errmsg("Force estimate to be at least one row, to avoid possible divide-by-zero when interpolating costs : %s", + hint->base.hint_str))); + result = clamp_row_est(result); + elog(DEBUG1, "adjusted rows %d to %d", (int) rows, (int) result); + + return result; +} + +/* * make_join_rel * Find or create a join RelOptInfo that represents the join of * the two given rels, and add to it path information for paths @@ -60,7 +92,7 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2) /* * If it's a plain inner join, then we won't have found anything in - * join_info_list. Make up a SpecialJoinInfo so that selectivity + * join_info_list. Make up a SpecialJoinInfo so that selectivity * estimation functions will know what's being joined. */ if (sjinfo == NULL) @@ -75,7 +107,10 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2) /* we don't bother trying to make the remaining fields valid */ sjinfo->lhs_strict = false; sjinfo->delay_upper_joins = false; - sjinfo->join_quals = NIL; + sjinfo->semi_can_btree = false; + sjinfo->semi_can_hash = false; + sjinfo->semi_operators = NIL; + sjinfo->semi_rhs_exprs = NIL; } /* @@ -85,6 +120,84 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2) joinrel = build_join_rel(root, joinrelids, rel1, rel2, sjinfo, &restrictlist); + /* !!! START: HERE IS THE PART WHICH ADDED FOR PG_HINT_PLAN !!! */ + { + RowsHint *rows_hint = NULL; + int i; + RowsHint *justforme = NULL; + RowsHint *domultiply = NULL; + + /* Search for applicable rows hint for this join node */ + for (i = 0; i < current_hint_state->num_hints[HINT_TYPE_ROWS]; i++) + { + rows_hint = current_hint_state->rows_hints[i]; + + /* + * Skip this rows_hint if it is invalid from the first or it + * doesn't target any join rels. + */ + if (!rows_hint->joinrelids || + rows_hint->base.state == HINT_STATE_ERROR) + continue; + + if (bms_equal(joinrelids, rows_hint->joinrelids)) + { + /* + * This joinrel is just the target of this rows_hint, so tweak + * rows estimation according to the hint. + */ + justforme = rows_hint; + } + else if (!(bms_is_subset(rows_hint->joinrelids, rel1->relids) || + bms_is_subset(rows_hint->joinrelids, rel2->relids)) && + bms_is_subset(rows_hint->joinrelids, joinrelids) && + rows_hint->value_type == RVT_MULTI) + { + /* + * If the rows_hint's target relids is not a subset of both of + * component rels and is a subset of this joinrel, ths hint's + * targets spread over both component rels. This menas that + * this hint has been never applied so far and this joinrel is + * the first (and only) chance to fire in current join tree. + * Only the multiplication hint has the cumulative nature so we + * apply only RVT_MULTI in this way. + */ + domultiply = rows_hint; + } + } + + if (justforme) + { + /* + * If a hint just for me is found, no other adjust method is + * useles, but this cannot be more than twice becuase this joinrel + * is already adjusted by this hint. + */ + if (justforme->base.state == HINT_STATE_NOTUSED) + joinrel->rows = adjust_rows(joinrel->rows, justforme); + } + else + { + if (domultiply) + { + /* + * If we have multiple routes up to this joinrel which are not + * applicable this hint, this multiply hint will applied more + * than twice. But there's no means to know of that, + * re-estimate the row number of this joinrel always just + * before applying the hint. This is a bit different from + * normal planner behavior but it doesn't harm so much. + */ + set_joinrel_size_estimates(root, joinrel, rel1, rel2, sjinfo, + restrictlist); + + joinrel->rows = adjust_rows(joinrel->rows, domultiply); + } + + } + } + /* !!! END: HERE IS THE PART WHICH ADDED FOR PG_HINT_PLAN !!! */ + /* * If we've already proven this join is empty, we needn't consider any * more paths for it.