]> granicus.if.org Git - postgresql/commitdiff
Clean up planner confusion between ncolumns and nkeycolumns.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 12 Feb 2019 23:38:32 +0000 (18:38 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 12 Feb 2019 23:38:32 +0000 (18:38 -0500)
We're only going to consider key columns when creating indexquals,
so there is no point in having the outer loops in indxpath.c iterate
further than nkeycolumns.

Doing so in match_pathkeys_to_index() is actually wrong, and would have
caused crashes by now, except that we have no index AMs supporting both
amcanorderbyop and amcaninclude.

It's also wrong in relation_has_unique_index_for().  The effect there is
to fail to prove uniqueness even when the index does prove it, if there
are extra columns.

Also future-proof examine_variable() for the day when extra columns can
be expressions, and fix what's either a thinko or just an oversight in
btcostestimate(): we should consider the number of key columns, not the
total, when deciding whether to derate correlation.

None of these things seemed important enough to risk changing in a
just-before-wrap patch, but since we're past the release wrap window,
time to fix 'em.

Discussion: https://postgr.es/m/25526.1549847928@sss.pgh.pa.us

src/backend/optimizer/path/indxpath.c
src/backend/utils/adt/selfuncs.c

index 2d5a09b1b458c7e50599df1a5b338c836509e7b0..e0933fc24d0c7cdaee46b0c5f18d404b39a2f66e 100644 (file)
@@ -253,7 +253,7 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
                IndexOptInfo *index = (IndexOptInfo *) lfirst(lc);
 
                /* Protect limited-size array in IndexClauseSets */
-               Assert(index->ncolumns <= INDEX_MAX_KEYS);
+               Assert(index->nkeycolumns <= INDEX_MAX_KEYS);
 
                /*
                 * Ignore partial indexes that do not match the query.
@@ -468,7 +468,7 @@ consider_index_join_clauses(PlannerInfo *root, RelOptInfo *rel,
         * relation itself is also included in the relids set.  considered_relids
         * lists all relids sets we've already tried.
         */
-       for (indexcol = 0; indexcol < index->ncolumns; indexcol++)
+       for (indexcol = 0; indexcol < index->nkeycolumns; indexcol++)
        {
                /* Consider each applicable simple join clause */
                considered_clauses += list_length(jclauseset->indexclauses[indexcol]);
@@ -623,7 +623,7 @@ get_join_index_paths(PlannerInfo *root, RelOptInfo *rel,
        /* Identify indexclauses usable with this relids set */
        MemSet(&clauseset, 0, sizeof(clauseset));
 
-       for (indexcol = 0; indexcol < index->ncolumns; indexcol++)
+       for (indexcol = 0; indexcol < index->nkeycolumns; indexcol++)
        {
                ListCell   *lc;
 
@@ -920,7 +920,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
        index_clauses = NIL;
        found_lower_saop_clause = false;
        outer_relids = bms_copy(rel->lateral_relids);
-       for (indexcol = 0; indexcol < index->ncolumns; indexcol++)
+       for (indexcol = 0; indexcol < index->nkeycolumns; indexcol++)
        {
                ListCell   *lc;
 
@@ -3237,11 +3237,12 @@ match_pathkeys_to_index(IndexOptInfo *index, List *pathkeys,
                        /*
                         * We allow any column of the index to match each pathkey; they
                         * don't have to match left-to-right as you might expect.  This is
-                        * correct for GiST, which is the sole existing AM supporting
-                        * amcanorderbyop.  We might need different logic in future for
-                        * other implementations.
+                        * correct for GiST, and it doesn't matter for SP-GiST because
+                        * that doesn't handle multiple columns anyway, and no other
+                        * existing AMs support amcanorderbyop.  We might need different
+                        * logic in future for other implementations.
                         */
-                       for (indexcol = 0; indexcol < index->ncolumns; indexcol++)
+                       for (indexcol = 0; indexcol < index->nkeycolumns; indexcol++)
                        {
                                Expr       *expr;
 
@@ -3672,7 +3673,7 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel,
                 * Try to find each index column in the lists of conditions.  This is
                 * O(N^2) or worse, but we expect all the lists to be short.
                 */
-               for (c = 0; c < ind->ncolumns; c++)
+               for (c = 0; c < ind->nkeycolumns; c++)
                {
                        bool            matched = false;
                        ListCell   *lc;
@@ -3747,8 +3748,8 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel,
                                break;                  /* no match; this index doesn't help us */
                }
 
-               /* Matched all columns of this index? */
-               if (c == ind->ncolumns)
+               /* Matched all key columns of this index? */
+               if (c == ind->nkeycolumns)
                        return true;
        }
 
index 1ef6faecd1eed7ea0c0f245dd9d7305f0790ea14..b9f99fa050b6f150adbae6acaba7d863ecb1bf33 100644 (file)
@@ -4869,6 +4869,10 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
                 * it to expressional index columns, in hopes of finding some
                 * statistics.
                 *
+                * Note that we consider all index columns including INCLUDE columns,
+                * since there could be stats for such columns.  But the test for
+                * uniqueness needs to be warier.
+                *
                 * XXX it's conceivable that there are multiple matches with different
                 * index opfamilies; if so, we need to pick one that matches the
                 * operator we are estimating for.  FIXME later.
@@ -4904,6 +4908,7 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
                                                 */
                                                if (index->unique &&
                                                        index->nkeycolumns == 1 &&
+                                                       pos == 0 &&
                                                        (index->indpred == NIL || index->predOK))
                                                        vardata->isunique = true;
 
@@ -7242,7 +7247,7 @@ btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
                        if (index->reverse_sort[0])
                                varCorrelation = -varCorrelation;
 
-                       if (index->ncolumns > 1)
+                       if (index->nkeycolumns > 1)
                                costs.indexCorrelation = varCorrelation * 0.75;
                        else
                                costs.indexCorrelation = varCorrelation;