choose-bitmap-and.patch
text/x-patch
Filename: choose-bitmap-and.patch
Type: text/x-patch
Part: 2
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/backend/optimizer/path/indxpath.c | 52 | 1 |
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)