diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index f295558..da5a98e 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -1371,7 +1371,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
 {
 	int			npaths = list_length(paths);
 	PathClauseUsage **pathinfoarray;
-	PathClauseUsage *pathinfo;
+	PathClauseUsage *pathinfo = NULL;
 	List	   *clauselist;
 	List	   *bestpaths = NIL;
 	Cost		bestcost = 0;
@@ -1431,6 +1431,10 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
 	 * regular qual clauses too, to have a more intelligent, but much more
 	 * expensive, check for redundancy --- but in most cases simple equality
 	 * seems to suffice.)
+	 *
+	 * It is too slow to compare paths by clause usage if there are too many
+	 * clauses, so in that case we skip the above algorithm and just return
+	 * the cheapest input path.
 	 */
 
 	/*
@@ -1447,6 +1451,14 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
 		Path	   *ipath = (Path *) lfirst(l);
 
 		pathinfo = classify_index_clause_usage(ipath, &clauselist);
+
+		/*
+		 * There are too many clauses to classify efficiently, switch
+		 * to a simpler algorithm.
+		 */
+		if (pathinfo == NULL)
+			break;
+
 		for (i = 0; i < npaths; i++)
 		{
 			if (bms_equal(pathinfo->clauseids, pathinfoarray[i]->clauseids))
@@ -1476,6 +1488,27 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
 	if (npaths == 1)
 		return pathinfoarray[0]->path;
 
+	/*
+	 * If there are too many different clauses to classify efficiently,
+	 * just return the cheapest input path.
+	 */
+	if (pathinfo == NULL)
+	{
+		Path *bestPath = NULL;
+		Cost bestCost = 0.;
+		foreach(l, paths)
+		{
+			Path *path = (Path *) lfirst(l);
+			Cost cost = bitmap_and_cost_est(root, rel, list_make1(path));
+			if (bestPath == NULL || cost < bestCost)
+			{
+				bestCost = cost;
+				bestPath = path;
+			}
+		}
+		return bestPath;
+	}
+
 	/* Sort the surviving paths by index access cost */
 	qsort(pathinfoarray, npaths, sizeof(PathClauseUsage *),
 		  path_usage_comparator);
@@ -1695,6 +1728,17 @@ bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths)
  * *clauselist is used and expanded as needed to identify all the distinct
  * clauses seen across successive calls.  Caller must initialize it to NIL
  * before first call of a set.
+ *
+ * We use linear search in list to find clauses in clauselist, so the time
+ * to classify the clauses grows quadratically with their number. To control
+ * the run time, this function returns NULL after clauselist length reaches
+ * some threshold, so that the caller can switch to a simpler algorithm.
+ *
+ * It could be possible to use a tree or a hash table instead of list to
+ * allows faster lookups, but we don't have comparison or hash function for
+ * the nodes. The nodeToString() is not suitable because the equality of string
+ * representation is not the same ad nodes being equal(). The string includes
+ * some fields that are ignored by equal(), such as token location.
  */
 static PathClauseUsage *
 classify_index_clause_usage(Path *path, List **clauselist)
@@ -1711,6 +1755,13 @@ classify_index_clause_usage(Path *path, List **clauselist)
 	result->preds = NIL;
 	find_indexpath_quals(path, &result->quals, &result->preds);
 
+	/* Bail out if there are too many clauses to classify efficiently */
+	if (list_length(result->quals) + list_length(result->preds)
+		+ list_length(*clauselist) > 1000)
+	{
+		return NULL;
+	}
+
 	/* Build up a bitmapset representing the quals and preds */
 	clauseids = NULL;
 	foreach(lc, result->quals)
