firtst release
Revision | 7cd601eb6e8d0dfa9ce9757626ac2c279698a4c7 (tree) |
---|---|
Time | 2014-09-05 13:20:04 |
Author | Kyotaro Horiguchi <horiguchi.kyotaro@lab....> |
Commiter | Kyotaro Horiguchi |
Fixed a bug that rows hint can be omitted on some condition.
A hint for higer level may be canceled by unnecessary reestimation
caused by a rows hint for lower level.
During making a joinrel, if there's a rows hint just matches the
joinrelids, and has already been applied on an earlier try for the same
joinrelids, and if there's another rows hint which is applicable on
either component of the join, the change of rownums made earlier is
canceled by the 'another' hint causing reestimation of the joinrel.
Finally the effect of the former hint disappears.
@@ -24,7 +24,7 @@ | ||
24 | 24 | |
25 | 25 | QUERY PLAN |
26 | 26 | ----------------------------------------------------------------------------- |
27 | - Nested Loop (cost=xxx rows=1 width=73) | |
27 | + Nested Loop (cost=xxx rows=20 width=73) | |
28 | 28 | -> Nested Loop (cost=xxx rows=2 width=59) |
29 | 29 | -> Values Scan on "*VALUES*" (cost=xxx rows=1 width=44) |
30 | 30 | -> Index Scan using t1_i1 on t1 (cost=xxx rows=1 width=15) |
@@ -2055,24 +2055,24 @@ error hint: | ||
2055 | 2055 | -- No. R-2-4-1 |
2056 | 2056 | \o results/R_2-4-1.out.log |
2057 | 2057 | EXPLAIN SELECT * FROM s1.t1, s1.t2, (VALUES(1,1,1,'1')) AS t3 (c1, c2, c3, c4) WHERE t1.c1 = t2.c1 AND t1.c1 = t3.c1; |
2058 | -/*+ Leading(t3 t1 t2) Rows(t3 t1 #2)Rows(t3 t1 t2 #2)*/ | |
2058 | +/*+ Leading(t3 t1 t2) Rows(t3 t1 #2)Rows(t3 t1 t2 #20)*/ | |
2059 | 2059 | EXPLAIN SELECT * FROM s1.t1, s1.t2, (VALUES(1,1,1,'1')) AS t3 (c1, c2, c3, c4) WHERE t1.c1 = t2.c1 AND t1.c1 = t3.c1; |
2060 | 2060 | LOG: pg_hint_plan: |
2061 | 2061 | used hint: |
2062 | 2062 | not used hint: |
2063 | 2063 | Leading(t3 t1 t2) |
2064 | 2064 | Rows(t1 t3 #2) |
2065 | -Rows(t1 t2 t3 #2) | |
2065 | +Rows(t1 t2 t3 #20) | |
2066 | 2066 | duplication hint: |
2067 | 2067 | error hint: |
2068 | 2068 | |
2069 | -/*+ Leading(*VALUES* t1 t2) Rows(*VALUES* t1 #2)Rows(*VALUES* t1 t2 #2)*/ | |
2069 | +/*+ Leading(*VALUES* t1 t2) Rows(*VALUES* t1 #2)Rows(*VALUES* t1 t2 #20)*/ | |
2070 | 2070 | EXPLAIN SELECT * FROM s1.t1, s1.t2, (VALUES(1,1,1,'1')) AS t3 (c1, c2, c3, c4) WHERE t1.c1 = t2.c1 AND t1.c1 = t3.c1; |
2071 | 2071 | LOG: pg_hint_plan: |
2072 | 2072 | used hint: |
2073 | 2073 | Leading(*VALUES* t1 t2) |
2074 | 2074 | Rows(*VALUES* t1 #2) |
2075 | -Rows(*VALUES* t1 t2 #2) | |
2075 | +Rows(*VALUES* t1 t2 #20) | |
2076 | 2076 | not used hint: |
2077 | 2077 | duplication hint: |
2078 | 2078 | error hint: |
@@ -62,9 +62,6 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2) | ||
62 | 62 | RelOptInfo *joinrel; |
63 | 63 | List *restrictlist; |
64 | 64 | |
65 | - RowsHint *rows_hint = NULL; | |
66 | - int i; | |
67 | - | |
68 | 65 | /* We should never try to join two overlapping sets of rels. */ |
69 | 66 | Assert(!bms_overlap(rel1->relids, rel2->relids)); |
70 | 67 |
@@ -116,61 +113,83 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2) | ||
116 | 113 | joinrel = build_join_rel(root, joinrelids, rel1, rel2, sjinfo, |
117 | 114 | &restrictlist); |
118 | 115 | |
119 | - /* Apply appropriate Rows hint to the join node, if any. */ | |
120 | - for (i = 0; i < current_hint->num_hints[HINT_TYPE_ROWS]; i++) | |
116 | + /* !!! START: HERE IS THE PART WHICH ADDED FOR PG_HINT_PLAN !!! */ | |
121 | 117 | { |
122 | - rows_hint = current_hint->rows_hints[i]; | |
123 | - | |
124 | - /* | |
125 | - * This Rows hint is invalid for some reason, or it contains no | |
126 | - * aliasname which exists in the query. | |
127 | - */ | |
128 | - if (!rows_hint->joinrelids || | |
129 | - rows_hint->base.state == HINT_STATE_ERROR) | |
130 | - continue; | |
118 | + RowsHint *rows_hint = NULL; | |
119 | + int i; | |
120 | + RowsHint *justforme = NULL; | |
121 | + RowsHint *domultiply = NULL; | |
131 | 122 | |
132 | - if (bms_equal(joinrelids, rows_hint->joinrelids)) | |
123 | + /* Search for applicable rows hint for this join node */ | |
124 | + for (i = 0; i < current_hint->num_hints[HINT_TYPE_ROWS]; i++) | |
133 | 125 | { |
126 | + rows_hint = current_hint->rows_hints[i]; | |
127 | + | |
134 | 128 | /* |
135 | - * This join RelOptInfo is exactly a Rows hint specifies, so adjust | |
136 | - * rows estimateion with the hint's content. Here we never have | |
137 | - * another hint which has same relation combination, so we can skip | |
138 | - * rest of hints. | |
129 | + * Skip this rows_hint if it is invalid from the first or it | |
130 | + * doesn't target any join rels. | |
139 | 131 | */ |
140 | - if (rows_hint->base.state == HINT_STATE_NOTUSED) | |
141 | - joinrel->rows = adjust_rows(joinrel->rows, rows_hint); | |
132 | + if (!rows_hint->joinrelids || | |
133 | + rows_hint->base.state == HINT_STATE_ERROR) | |
134 | + continue; | |
135 | + | |
136 | + if (bms_equal(joinrelids, rows_hint->joinrelids)) | |
137 | + { | |
138 | + /* | |
139 | + * This joinrel is just the target of this rows_hint, so tweak | |
140 | + * rows estimation according to the hint. | |
141 | + */ | |
142 | + justforme = rows_hint; | |
143 | + } | |
144 | + else if (!(bms_is_subset(rows_hint->joinrelids, rel1->relids) || | |
145 | + bms_is_subset(rows_hint->joinrelids, rel2->relids)) && | |
146 | + bms_is_subset(rows_hint->joinrelids, joinrelids) && | |
147 | + rows_hint->value_type == RVT_MULTI) | |
148 | + { | |
149 | + /* | |
150 | + * If the rows_hint's target relids is not a subset of both of | |
151 | + * component rels and is a subset of this joinrel, ths hint's | |
152 | + * targets spread over both component rels. This menas that | |
153 | + * this hint has been never applied so far and this joinrel is | |
154 | + * the first (and only) chance to fire in current join tree. | |
155 | + * Only the multiplication hint has the cumulative nature so we | |
156 | + * apply only RVT_MULTI in this way. | |
157 | + */ | |
158 | + domultiply = rows_hint; | |
159 | + } | |
142 | 160 | } |
143 | - else if (bms_is_subset(rows_hint->joinrelids, rel1->relids) || | |
144 | - bms_is_subset(rows_hint->joinrelids, rel2->relids)) | |
161 | + | |
162 | + if (justforme) | |
145 | 163 | { |
146 | 164 | /* |
147 | - * Otherwise if the relation combination specified in thee Rows | |
148 | - * hint is subset of the set of join elements, re-estimate rows and | |
149 | - * costs again to reflect the adjustment done in down. This is | |
150 | - * necessary for the first permutation of the combination the | |
151 | - * relations, but it's difficult to determine that this is the | |
152 | - * first, so do this everytime. | |
165 | + * If a hint just for me is found, no other adjust method is | |
166 | + * useles, but this cannot be more than twice becuase this joinrel | |
167 | + * is already adjusted by this hint. | |
153 | 168 | */ |
154 | - set_joinrel_size_estimates(root, joinrel, rel1, rel2, sjinfo, | |
155 | - restrictlist); | |
169 | + if (justforme->base.state == HINT_STATE_NOTUSED) | |
170 | + joinrel->rows = adjust_rows(joinrel->rows, justforme); | |
156 | 171 | } |
157 | - else if (bms_is_subset(rows_hint->joinrelids, joinrelids)) | |
172 | + else | |
158 | 173 | { |
159 | - /* | |
160 | - * If the combination specifed in the Rows hints is subset of the | |
161 | - * join relation and spreads over both children, | |
162 | - * | |
163 | - * We do adjust rows estimation only when the value type was | |
164 | - * multiplication, because other value types are meanless. | |
165 | - */ | |
166 | - if (rows_hint->value_type == RVT_MULTI) | |
174 | + if (domultiply) | |
167 | 175 | { |
176 | + /* | |
177 | + * If we have multiple routes up to this joinrel which are not | |
178 | + * applicable this hint, this multiply hint will applied more | |
179 | + * than twice. But there's no means to know of that, | |
180 | + * re-estimate the row number of this joinrel always just | |
181 | + * before applying the hint. This is a bit different from | |
182 | + * normal planner behavior but it doesn't harm so much. | |
183 | + */ | |
168 | 184 | set_joinrel_size_estimates(root, joinrel, rel1, rel2, sjinfo, |
169 | 185 | restrictlist); |
170 | - joinrel->rows = adjust_rows(joinrel->rows, rows_hint); | |
186 | + | |
187 | + joinrel->rows = adjust_rows(joinrel->rows, domultiply); | |
171 | 188 | } |
189 | + | |
172 | 190 | } |
173 | 191 | } |
192 | + /* !!! END: HERE IS THE PART WHICH ADDED FOR PG_HINT_PLAN !!! */ | |
174 | 193 | |
175 | 194 | /* |
176 | 195 | * If we've already proven this join is empty, we needn't consider any |
@@ -1021,9 +1021,9 @@ EXPLAIN SELECT * FROM s1.r4 t1, s1.r5 t2 WHERE t1.c1 = t2.c1; | ||
1021 | 1021 | -- No. R-2-4-1 |
1022 | 1022 | \o results/R_2-4-1.out.log |
1023 | 1023 | EXPLAIN SELECT * FROM s1.t1, s1.t2, (VALUES(1,1,1,'1')) AS t3 (c1, c2, c3, c4) WHERE t1.c1 = t2.c1 AND t1.c1 = t3.c1; |
1024 | -/*+ Leading(t3 t1 t2) Rows(t3 t1 #2)Rows(t3 t1 t2 #2)*/ | |
1024 | +/*+ Leading(t3 t1 t2) Rows(t3 t1 #2)Rows(t3 t1 t2 #20)*/ | |
1025 | 1025 | EXPLAIN SELECT * FROM s1.t1, s1.t2, (VALUES(1,1,1,'1')) AS t3 (c1, c2, c3, c4) WHERE t1.c1 = t2.c1 AND t1.c1 = t3.c1; |
1026 | -/*+ Leading(*VALUES* t1 t2) Rows(*VALUES* t1 #2)Rows(*VALUES* t1 t2 #2)*/ | |
1026 | +/*+ Leading(*VALUES* t1 t2) Rows(*VALUES* t1 #2)Rows(*VALUES* t1 t2 #20)*/ | |
1027 | 1027 | EXPLAIN SELECT * FROM s1.t1, s1.t2, (VALUES(1,1,1,'1')) AS t3 (c1, c2, c3, c4) WHERE t1.c1 = t2.c1 AND t1.c1 = t3.c1; |
1028 | 1028 | \o |
1029 | 1029 | \! sed 's/cost=[\.0-9]*/cost=xxx/' results/R_2-4-1.out.log > results/R_2-4-1.out |