diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 873a764..561f5dc 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -67,6 +67,7 @@ join_search_hook_type join_search_hook = NULL; static void set_base_rel_consider_startup(PlannerInfo *root); static void set_base_rel_sizes(PlannerInfo *root); static void set_base_rel_pathlists(PlannerInfo *root); +static void mark_useful_foreign_keys(PlannerInfo *root); static void set_rel_size(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte); static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, @@ -168,6 +169,7 @@ make_one_rel(PlannerInfo *root, List *joinlist) */ set_base_rel_sizes(root); set_base_rel_pathlists(root); + mark_useful_foreign_keys(root); /* * Generate access paths for the entire join tree. @@ -301,6 +303,76 @@ set_base_rel_pathlists(PlannerInfo *root) } /* + * mark_useful_foreign_keys + * Determine which of the foreign keys of each relation have a remote + * possibility of being referenced by some join in the query. Any of which + * that have no chance of being referenced are unlikely to be of any use + * during planning, and can most likely be ignored for most cases. + */ +static void +mark_useful_foreign_keys(PlannerInfo *root) +{ + HTAB *htab; + HASHCTL hash_ctl; + Index rti; + ListCell *lc; + + memset(&hash_ctl, 0, sizeof(hash_ctl)); + hash_ctl.keysize = sizeof(Oid); + hash_ctl.entrysize = sizeof(Oid); + hash_ctl.hcxt = CurrentMemoryContext; + htab = hash_create("mark_useful_foreign_keys", + root->simple_rel_array_size, + &hash_ctl, + HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); + + /* build a hash table with all rel OIDs that are in the query */ + for (rti = 1; rti < root->simple_rel_array_size; rti++) + { + RelOptInfo *rel = root->simple_rel_array[rti]; + RangeTblEntry *rte; + + if (rel == NULL) + continue; + + /* ignore RTEs that are "other rels" */ + if (rel->reloptkind != RELOPT_BASEREL) + continue; + + rte = root->simple_rte_array[rti]; + + (void) hash_search(htab, (void *) &(rte->relid), HASH_ENTER, NULL); + } + + /* XXX do we need to add entries for the append_rel_list here? */ + + /* + * Now go over each rel and set each foreign key's 'possibleRef' according + * to if the FKs confrelid was found to be in the query or not. + */ + for (rti = 1; rti < root->simple_rel_array_size; rti++) + { + RelOptInfo *rel = root->simple_rel_array[rti]; + + if (rel == NULL) + continue; + + /* ignore RTEs that are "other rels" */ + if (rel->reloptkind != RELOPT_BASEREL) + continue; + + foreach(lc, rel->fkeylist) + { + ForeignKeyOptInfo *fkinfo = (ForeignKeyOptInfo *) lfirst(lc); + hash_search(htab, (void *) &(fkinfo->confrelid), HASH_FIND, &(fkinfo->possibleRef)); + } + } + + /* Done with the hash table. */ + hash_destroy(htab); +} + +/* * set_rel_size * Set size estimates for a base relation */ diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index fcb1873..87c0aaf 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -3944,13 +3944,13 @@ quals_match_foreign_key(PlannerInfo *root, ForeignKeyOptInfo *fkinfo, if (i > 0 && bms_is_member(quallstidx, qualmatches)) continue; - /* - * Here since 'usefulquals' only contains bitmap indexes for quals - * of type "var op var" we can safely skip checking this. - */ rinfo = (RestrictInfo *) lfirst(lc); clause = (OpExpr *) rinfo->clause; + /* only OpExprs are useful for consideration */ + if (!IsA(clause, OpExpr)) + continue; + /* * If the operator does not match then there's little point in * checking the operands. @@ -4099,6 +4099,13 @@ find_best_foreign_key_quals(PlannerInfo *root, RelOptInfo *fkrel, Bitmapset *qualsmatched; /* + * Skip any foreign keys where we determined the referenced rel was + * not part of this query. + */ + if (!fkinfo->possibleRef) + continue; + + /* * We make no attempt in checking that this foreign key actually * references 'foreignrel', the reasoning here is that we may be able * to match the foreign key to an eclass member Var of a RestrictInfo diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 45739c3..ba359be 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -642,7 +642,7 @@ typedef struct ForeignKeyOptInfo int *conkeys; /* attnums of columns in the constrained table */ int *confkeys; /* attnums of columns in the referenced table */ Oid *conpfeqop; /* OIDs of equality operators used by the FK */ - + bool possibleRef; /* confrelid is in this query */ } ForeignKeyOptInfo; /*