8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
21
21
#include "optimizer/restrictinfo.h"
22
22
#include "optimizer/tlist.h"
23
23
#include "parser/parsetree.h"
24
+ #include "utils/hsearch.h"
24
25
25
26
27
+ typedef struct JoinHashEntry
28
+ {
29
+ Relids join_relids ; /* hash key --- MUST BE FIRST */
30
+ RelOptInfo * join_rel ;
31
+ } JoinHashEntry ;
32
+
26
33
static RelOptInfo * make_reloptinfo (PlannerInfo * root , int relid ,
27
34
RelOptKind reloptkind );
28
35
static void build_joinrel_tlist (PlannerInfo * root , RelOptInfo * joinrel ,
@@ -197,6 +204,47 @@ find_base_rel(PlannerInfo *root, int relid)
197
204
return NULL ; /* keep compiler quiet */
198
205
}
199
206
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
+
200
248
/*
201
249
* find_join_rel
202
250
* Returns relation entry corresponding to 'relids' (a set of RT indexes),
@@ -205,14 +253,44 @@ find_base_rel(PlannerInfo *root, int relid)
205
253
RelOptInfo *
206
254
find_join_rel (PlannerInfo * root , Relids relids )
207
255
{
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 );
209
262
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 )
211
272
{
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 ;
213
286
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
+ }
216
294
}
217
295
218
296
return NULL ;
@@ -329,9 +407,24 @@ build_join_rel(PlannerInfo *root,
329
407
jointype , restrictlist );
330
408
331
409
/*
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!
333
413
*/
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
+ }
335
428
336
429
return joinrel ;
337
430
}
0 commit comments