88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.68 2005/06/06 04:13:36 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.69 2005/06/08 23:02:05 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
2121#include "optimizer/restrictinfo.h"
2222#include "optimizer/tlist.h"
2323#include "parser/parsetree.h"
24+ #include "utils/hsearch.h"
2425
2526
27+ typedef struct JoinHashEntry
28+ {
29+ Relids join_relids ;/* hash key --- MUST BE FIRST */
30+ RelOptInfo * join_rel ;
31+ }JoinHashEntry ;
32+
2633static RelOptInfo * make_reloptinfo (PlannerInfo * root ,int relid ,
2734RelOptKind reloptkind );
2835static void build_joinrel_tlist (PlannerInfo * root ,RelOptInfo * joinrel ,
@@ -197,6 +204,47 @@ find_base_rel(PlannerInfo *root, int relid)
197204return NULL ;/* keep compiler quiet */
198205}
199206
207+ /*
208+ * build_join_rel_hash
209+ * Construct the auxiliary hash table for join relations.
210+ */
211+ static void
212+ build_join_rel_hash (PlannerInfo * root )
213+ {
214+ HTAB * hashtab ;
215+ HASHCTL hash_ctl ;
216+ ListCell * l ;
217+
218+ /* Create the hash table */
219+ MemSet (& hash_ctl ,0 ,sizeof (hash_ctl ));
220+ hash_ctl .keysize = sizeof (Relids );
221+ hash_ctl .entrysize = sizeof (JoinHashEntry );
222+ hash_ctl .hash = bitmap_hash ;
223+ hash_ctl .match = bitmap_match ;
224+ hash_ctl .hcxt = CurrentMemoryContext ;
225+ hashtab = hash_create ("JoinRelHashTable" ,
226+ 256L ,
227+ & hash_ctl ,
228+ HASH_ELEM |HASH_FUNCTION |HASH_COMPARE |HASH_CONTEXT );
229+
230+ /* Insert all the already-existing joinrels */
231+ foreach (l ,root -> join_rel_list )
232+ {
233+ RelOptInfo * rel = (RelOptInfo * )lfirst (l );
234+ JoinHashEntry * hentry ;
235+ bool found ;
236+
237+ hentry = (JoinHashEntry * )hash_search (hashtab ,
238+ & (rel -> relids ),
239+ HASH_ENTER ,
240+ & found );
241+ Assert (!found );
242+ hentry -> join_rel = rel ;
243+ }
244+
245+ root -> join_rel_hash = hashtab ;
246+ }
247+
200248/*
201249 * find_join_rel
202250 * Returns relation entry corresponding to 'relids' (a set of RT indexes),
@@ -205,14 +253,44 @@ find_base_rel(PlannerInfo *root, int relid)
205253RelOptInfo *
206254find_join_rel (PlannerInfo * root ,Relids relids )
207255{
208- ListCell * l ;
256+ /*
257+ * Switch to using hash lookup when list grows "too long". The threshold
258+ * is arbitrary and is known only here.
259+ */
260+ if (!root -> join_rel_hash && list_length (root -> join_rel_list )> 32 )
261+ build_join_rel_hash (root );
209262
210- foreach (l ,root -> join_rel_list )
263+ /*
264+ * Use either hashtable lookup or linear search, as appropriate.
265+ *
266+ * Note: the seemingly redundant hashkey variable is used to avoid
267+ * taking the address of relids; unless the compiler is exceedingly
268+ * smart, doing so would force relids out of a register and thus
269+ * probably slow down the list-search case.
270+ */
271+ if (root -> join_rel_hash )
211272{
212- RelOptInfo * rel = (RelOptInfo * )lfirst (l );
273+ Relids hashkey = relids ;
274+ JoinHashEntry * hentry ;
275+
276+ hentry = (JoinHashEntry * )hash_search (root -> join_rel_hash ,
277+ & hashkey ,
278+ HASH_FIND ,
279+ NULL );
280+ if (hentry )
281+ return hentry -> join_rel ;
282+ }
283+ else
284+ {
285+ ListCell * l ;
213286
214- if (bms_equal (rel -> relids ,relids ))
215- return rel ;
287+ foreach (l ,root -> join_rel_list )
288+ {
289+ RelOptInfo * rel = (RelOptInfo * )lfirst (l );
290+
291+ if (bms_equal (rel -> relids ,relids ))
292+ return rel ;
293+ }
216294}
217295
218296return NULL ;
@@ -329,9 +407,24 @@ build_join_rel(PlannerInfo *root,
329407jointype ,restrictlist );
330408
331409/*
332- * Add the joinrel to the query's joinrel list.
410+ * Add the joinrel to the query's joinrel list, and store it into
411+ * the auxiliary hashtable if there is one. NB: GEQO requires us
412+ * to append the new joinrel to the end of the list!
333413 */
334- root -> join_rel_list = lcons (joinrel ,root -> join_rel_list );
414+ root -> join_rel_list = lappend (root -> join_rel_list ,joinrel );
415+
416+ if (root -> join_rel_hash )
417+ {
418+ JoinHashEntry * hentry ;
419+ bool found ;
420+
421+ hentry = (JoinHashEntry * )hash_search (root -> join_rel_hash ,
422+ & (joinrel -> relids ),
423+ HASH_ENTER ,
424+ & found );
425+ Assert (!found );
426+ hentry -> join_rel = joinrel ;
427+ }
335428
336429return joinrel ;
337430}