IndexClauseSet *eclauseset,
                               List **bitindexpaths,
                               List *indexjoinclauses,
+                              int considered_clauses,
                               List **considered_relids);
 static void get_join_index_paths(PlannerInfo *root, RelOptInfo *rel,
                     IndexOptInfo *index,
                     List **bitindexpaths,
                     Relids relids,
                     List **considered_relids);
+static bool eclass_already_used(EquivalenceClass *parent_ec, Relids oldrelids,
+                   List *indexjoinclauses);
 static bool bms_equal_any(Relids relids, List *relids_list);
 static void get_index_paths(PlannerInfo *root, RelOptInfo *rel,
                IndexOptInfo *index, IndexClauseSet *clauses,
                            IndexClauseSet *eclauseset,
                            List **bitindexpaths)
 {
+   int         considered_clauses = 0;
    List       *considered_relids = NIL;
    int         indexcol;
 
     * filter (qpqual); which is where an available clause would end up being
     * applied if we omit it from the indexquals.
     *
-    * This looks expensive, but in practical cases there won't be very many
-    * distinct sets of outer rels to consider.
+    * This looks expensive, but in most practical cases there won't be very
+    * many distinct sets of outer rels to consider.  As a safety valve when
+    * that's not true, we use a heuristic: limit the number of outer rel sets
+    * considered to a multiple of the number of clauses considered.  (We'll
+    * always consider using each individual join clause, though.)
     *
     * For simplicity in selecting relevant clauses, we represent each set of
     * outer rels as a maximum set of clause_relids --- that is, the indexed
    for (indexcol = 0; indexcol < index->ncolumns; indexcol++)
    {
        /* Consider each applicable simple join clause */
+       considered_clauses += list_length(jclauseset->indexclauses[indexcol]);
        consider_index_join_outer_rels(root, rel, index,
                                       rclauseset, jclauseset, eclauseset,
                                       bitindexpaths,
                                       jclauseset->indexclauses[indexcol],
+                                      considered_clauses,
                                       &considered_relids);
        /* Consider each applicable eclass join clause */
+       considered_clauses += list_length(eclauseset->indexclauses[indexcol]);
        consider_index_join_outer_rels(root, rel, index,
                                       rclauseset, jclauseset, eclauseset,
                                       bitindexpaths,
                                       eclauseset->indexclauses[indexcol],
+                                      considered_clauses,
                                       &considered_relids);
    }
 }
  * 'rel', 'index', 'rclauseset', 'jclauseset', 'eclauseset', and
  *     'bitindexpaths' as above
  * 'indexjoinclauses' is a list of RestrictInfos for join clauses
+ * 'considered_clauses' is the total number of clauses considered (so far)
  * '*considered_relids' is a list of all relids sets already considered
  */
 static void
                               IndexClauseSet *eclauseset,
                               List **bitindexpaths,
                               List *indexjoinclauses,
+                              int considered_clauses,
                               List **considered_relids)
 {
    ListCell   *lc;
        /*
         * Generate the union of this clause's relids set with each
         * previously-tried set.  This ensures we try this clause along with
-        * every interesting subset of previous clauses.
+        * every interesting subset of previous clauses.  However, to avoid
+        * exponential growth of planning time when there are many clauses,
+        * limit the number of relid sets accepted to 10 * considered_clauses.
         *
         * Note: get_join_index_paths adds entries to *considered_relids, but
         * it prepends them to the list, so that we won't visit new entries
            if (bms_subset_compare(clause_relids, oldrelids) != BMS_DIFFERENT)
                continue;
 
+           /*
+            * If this clause was derived from an equivalence class, the
+            * clause list may contain other clauses derived from the same
+            * eclass.  We should not consider that combining this clause with
+            * one of those clauses generates a usefully different
+            * parameterization; so skip if any clause derived from the same
+            * eclass would already have been included when using oldrelids.
+            */
+           if (rinfo->parent_ec &&
+               eclass_already_used(rinfo->parent_ec, oldrelids,
+                                   indexjoinclauses))
+               continue;
+
+           /*
+            * If the number of relid sets considered exceeds our heuristic
+            * limit, stop considering combinations of clauses.  We'll still
+            * consider the current clause alone, though (below this loop).
+            */
+           if (list_length(*considered_relids) >= 10 * considered_clauses)
+               break;
+
            /* OK, try the union set */
            get_join_index_paths(root, rel, index,
                                 rclauseset, jclauseset, eclauseset,
    *considered_relids = lcons(relids, *considered_relids);
 }
 
+/*
+ * eclass_already_used
+ *     True if any join clause usable with oldrelids was generated from
+ *     the specified equivalence class.
+ */
+static bool
+eclass_already_used(EquivalenceClass *parent_ec, Relids oldrelids,
+                   List *indexjoinclauses)
+{
+   ListCell   *lc;
+
+   foreach(lc, indexjoinclauses)
+   {
+       RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
+
+       if (rinfo->parent_ec == parent_ec &&
+           bms_is_subset(rinfo->clause_relids, oldrelids))
+           return true;
+   }
+   return false;
+}
+
 /*
  * bms_equal_any
  *     True if relids is bms_equal to any member of relids_list