|
8 | 8 | * |
9 | 9 | * |
10 | 10 | * IDENTIFICATION |
11 | | - * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.131 2010/03/22 13:57:15 tgl Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.132 2010/03/28 22:59:32 tgl Exp $ |
12 | 12 | * |
13 | 13 | *------------------------------------------------------------------------- |
14 | 14 | */ |
|
22 | 22 | #include"optimizer/paths.h" |
23 | 23 |
|
24 | 24 |
|
25 | | -staticbooljoin_is_removable(PlannerInfo*root,RelOptInfo*joinrel, |
26 | | -RelOptInfo*outerrel,RelOptInfo*innerrel, |
27 | | -List*restrictlist,JoinTypejointype); |
28 | | -staticvoidgenerate_outer_only(PlannerInfo*root,RelOptInfo*joinrel, |
29 | | -RelOptInfo*outerrel); |
30 | 25 | staticvoidsort_inner_and_outer(PlannerInfo*root,RelOptInfo*joinrel, |
31 | 26 | RelOptInfo*outerrel,RelOptInfo*innerrel, |
32 | 27 | List*restrictlist,List*mergeclause_list, |
@@ -83,27 +78,11 @@ add_paths_to_joinrel(PlannerInfo *root, |
83 | 78 | { |
84 | 79 | List*mergeclause_list=NIL; |
85 | 80 |
|
86 | | -/* |
87 | | - * 0. Consider join removal. This is always the most efficient strategy, |
88 | | - * so if it works, there's no need to consider anything further. |
89 | | - */ |
90 | | -if (join_is_removable(root,joinrel,outerrel,innerrel, |
91 | | -restrictlist,jointype)) |
92 | | -{ |
93 | | -generate_outer_only(root,joinrel,outerrel); |
94 | | -return; |
95 | | -} |
96 | | - |
97 | 81 | /* |
98 | 82 | * Find potential mergejoin clauses. We can skip this if we are not |
99 | 83 | * interested in doing a mergejoin. However, mergejoin is currently our |
100 | 84 | * only way of implementing full outer joins, so override mergejoin |
101 | 85 | * disable if it's a full join. |
102 | | - * |
103 | | - * Note: do this after join_is_removable(), because this sets the |
104 | | - * outer_is_left flags in the mergejoin clauses, while join_is_removable |
105 | | - * uses those flags for its own purposes. Currently, they set the flags |
106 | | - * the same way anyway, but let's avoid unnecessary entanglement. |
107 | 86 | */ |
108 | 87 | if (enable_mergejoin||jointype==JOIN_FULL) |
109 | 88 | mergeclause_list=select_mergejoin_clauses(root, |
@@ -185,188 +164,6 @@ clause_sides_match_join(RestrictInfo *rinfo, RelOptInfo *outerrel, |
185 | 164 | return false;/* no good for these input relations */ |
186 | 165 | } |
187 | 166 |
|
188 | | -/* |
189 | | - * join_is_removable |
190 | | - * Determine whether we need not perform the join at all, because |
191 | | - * it will just duplicate its left input. |
192 | | - * |
193 | | - * This is true for a left join for which the join condition cannot match |
194 | | - * more than one inner-side row. (There are other possibly interesting |
195 | | - * cases, but we don't have the infrastructure to prove them.) We also |
196 | | - * have to check that the inner side doesn't generate any variables needed |
197 | | - * above the join. |
198 | | - * |
199 | | - * Note: there is no need to consider the symmetrical case of duplicating the |
200 | | - * right input, because add_paths_to_joinrel() will be called with each rel |
201 | | - * on the outer side. |
202 | | - */ |
203 | | -staticbool |
204 | | -join_is_removable(PlannerInfo*root, |
205 | | -RelOptInfo*joinrel, |
206 | | -RelOptInfo*outerrel, |
207 | | -RelOptInfo*innerrel, |
208 | | -List*restrictlist, |
209 | | -JoinTypejointype) |
210 | | -{ |
211 | | -List*clause_list=NIL; |
212 | | -ListCell*l; |
213 | | -intattroff; |
214 | | - |
215 | | -/* |
216 | | - * Currently, we only know how to remove left joins to a baserel with |
217 | | - * unique indexes.We can check most of these criteria pretty trivially |
218 | | - * to avoid doing useless extra work. But checking whether any of the |
219 | | - * indexes are unique would require iterating over the indexlist, so for |
220 | | - * now we just make sure there are indexes of some sort or other. If none |
221 | | - * of them are unique, join removal will still fail, just slightly later. |
222 | | - */ |
223 | | -if (jointype!=JOIN_LEFT|| |
224 | | -innerrel->reloptkind==RELOPT_JOINREL|| |
225 | | -innerrel->rtekind!=RTE_RELATION|| |
226 | | -innerrel->indexlist==NIL) |
227 | | -return false; |
228 | | - |
229 | | -/* |
230 | | - * We can't remove the join if any inner-rel attributes are used above the |
231 | | - * join. |
232 | | - * |
233 | | - * Note that this test only detects use of inner-rel attributes in higher |
234 | | - * join conditions and the target list. There might be such attributes in |
235 | | - * pushed-down conditions at this join, too. We check that case below. |
236 | | - * |
237 | | - * As a micro-optimization, it seems better to start with max_attr and |
238 | | - * count down rather than starting with min_attr and counting up, on the |
239 | | - * theory that the system attributes are somewhat less likely to be wanted |
240 | | - * and should be tested last. |
241 | | - */ |
242 | | -for (attroff=innerrel->max_attr-innerrel->min_attr; |
243 | | -attroff >=0; |
244 | | -attroff--) |
245 | | -{ |
246 | | -if (!bms_is_subset(innerrel->attr_needed[attroff],joinrel->relids)) |
247 | | -return false; |
248 | | -} |
249 | | - |
250 | | -/* |
251 | | - * Similarly check that the inner rel doesn't produce any PlaceHolderVars |
252 | | - * that will be used above the join. |
253 | | - */ |
254 | | -foreach(l,root->placeholder_list) |
255 | | -{ |
256 | | -PlaceHolderInfo*phinfo= (PlaceHolderInfo*)lfirst(l); |
257 | | - |
258 | | -if (bms_is_subset(phinfo->ph_eval_at,innerrel->relids)&& |
259 | | -!bms_is_subset(phinfo->ph_needed,joinrel->relids)) |
260 | | -return false; |
261 | | -} |
262 | | - |
263 | | -/* |
264 | | - * Search for mergejoinable clauses that constrain the inner rel against |
265 | | - * either the outer rel or a pseudoconstant. If an operator is |
266 | | - * mergejoinable then it behaves like equality for some btree opclass, so |
267 | | - * it's what we want. The mergejoinability test also eliminates clauses |
268 | | - * containing volatile functions, which we couldn't depend on. |
269 | | - */ |
270 | | -foreach(l,restrictlist) |
271 | | -{ |
272 | | -RestrictInfo*restrictinfo= (RestrictInfo*)lfirst(l); |
273 | | - |
274 | | -/* |
275 | | - * If we find a pushed-down clause, it must have come from above the |
276 | | - * outer join and it must contain references to the inner rel.(If it |
277 | | - * had only outer-rel variables, it'd have been pushed down into the |
278 | | - * outer rel.)Therefore, we can conclude that join removal is unsafe |
279 | | - * without any examination of the clause contents. |
280 | | - */ |
281 | | -if (restrictinfo->is_pushed_down) |
282 | | -return false; |
283 | | - |
284 | | -/* Ignore if it's not a mergejoinable clause */ |
285 | | -if (!restrictinfo->can_join|| |
286 | | -restrictinfo->mergeopfamilies==NIL) |
287 | | -continue;/* not mergejoinable */ |
288 | | - |
289 | | -/* |
290 | | - * Check if clause has the form "outer op inner" or "inner op outer". |
291 | | - */ |
292 | | -if (!clause_sides_match_join(restrictinfo,outerrel,innerrel)) |
293 | | -continue;/* no good for these input relations */ |
294 | | - |
295 | | -/* OK, add to list */ |
296 | | -clause_list=lappend(clause_list,restrictinfo); |
297 | | -} |
298 | | - |
299 | | -/* Now examine the rel's restriction clauses for var = const clauses */ |
300 | | -foreach(l,innerrel->baserestrictinfo) |
301 | | -{ |
302 | | -RestrictInfo*restrictinfo= (RestrictInfo*)lfirst(l); |
303 | | - |
304 | | -/* |
305 | | - * Note: can_join won't be set for a restriction clause, but |
306 | | - * mergeopfamilies will be if it has a mergejoinable operator and |
307 | | - * doesn't contain volatile functions. |
308 | | - */ |
309 | | -if (restrictinfo->mergeopfamilies==NIL) |
310 | | -continue;/* not mergejoinable */ |
311 | | - |
312 | | -/* |
313 | | - * The clause certainly doesn't refer to anything but the given rel. |
314 | | - * If either side is pseudoconstant then we can use it. |
315 | | - */ |
316 | | -if (bms_is_empty(restrictinfo->left_relids)) |
317 | | -{ |
318 | | -/* righthand side is inner */ |
319 | | -restrictinfo->outer_is_left= true; |
320 | | -} |
321 | | -elseif (bms_is_empty(restrictinfo->right_relids)) |
322 | | -{ |
323 | | -/* lefthand side is inner */ |
324 | | -restrictinfo->outer_is_left= false; |
325 | | -} |
326 | | -else |
327 | | -continue; |
328 | | - |
329 | | -/* OK, add to list */ |
330 | | -clause_list=lappend(clause_list,restrictinfo); |
331 | | -} |
332 | | - |
333 | | -/* Now examine the indexes to see if we have a matching unique index */ |
334 | | -if (relation_has_unique_index_for(root,innerrel,clause_list)) |
335 | | -return true; |
336 | | - |
337 | | -/* |
338 | | - * Some day it would be nice to check for other methods of establishing |
339 | | - * distinctness. |
340 | | - */ |
341 | | -return false; |
342 | | -} |
343 | | - |
344 | | -/* |
345 | | - * generate_outer_only |
346 | | - * Generate "join" paths when we have found the join is removable. |
347 | | - */ |
348 | | -staticvoid |
349 | | -generate_outer_only(PlannerInfo*root,RelOptInfo*joinrel, |
350 | | -RelOptInfo*outerrel) |
351 | | -{ |
352 | | -ListCell*lc; |
353 | | - |
354 | | -/* |
355 | | - * For the moment, replicate all of the outerrel's paths as join paths. |
356 | | - * Some of them might not really be interesting above the join, if they |
357 | | - * have sort orderings that have no real use except to do a mergejoin for |
358 | | - * the join we've just found we don't need. But distinguishing that case |
359 | | - * probably isn't worth the extra code it would take. |
360 | | - */ |
361 | | -foreach(lc,outerrel->pathlist) |
362 | | -{ |
363 | | -Path*outerpath= (Path*)lfirst(lc); |
364 | | - |
365 | | -add_path(joinrel, (Path*) |
366 | | -create_noop_path(root,joinrel,outerpath)); |
367 | | -} |
368 | | -} |
369 | | - |
370 | 167 | /* |
371 | 168 | * sort_inner_and_outer |
372 | 169 | * Create mergejoin join paths by explicitly sorting both the outer and |
|