mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
Allow Incremental Sorts on GiST and SP-GiST indexes
Previously an "amcanorderbyop" index would only be used when the index could provide sorted results which satisfied all query_pathkeys. Here we relax this so that we also allow these indexes to be considered by the planner when they only provide partially sorted results. This allows the planner to later consider making use of an Incremental Sort to satisfy the remaining pathkeys. This change is particularly useful for KNN-type queries which contain a LIMIT clause and an additional ORDER BY clause for a non-indexed column. Author: Miroslav Bendik Reviewed-by: Richard Guo, David Rowley Discussion: https://postgr.es/m/CAPoEpV0QYDtzjwamwWUBqyWpaCVbJV2d6qOD7Uy09bWn47PJtw%40mail.gmail.com
This commit is contained in:
@@ -974,14 +974,20 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
|
||||
}
|
||||
else if (index->amcanorderbyop && pathkeys_possibly_useful)
|
||||
{
|
||||
/* see if we can generate ordering operators for query_pathkeys */
|
||||
/*
|
||||
* See if we can generate ordering operators for query_pathkeys or at
|
||||
* least some prefix thereof. Matching to just a prefix of the
|
||||
* query_pathkeys will allow an incremental sort to be considered on
|
||||
* the index's partially sorted results.
|
||||
*/
|
||||
match_pathkeys_to_index(index, root->query_pathkeys,
|
||||
&orderbyclauses,
|
||||
&orderbyclausecols);
|
||||
if (orderbyclauses)
|
||||
if (list_length(root->query_pathkeys) == list_length(orderbyclauses))
|
||||
useful_pathkeys = root->query_pathkeys;
|
||||
else
|
||||
useful_pathkeys = NIL;
|
||||
useful_pathkeys = list_copy_head(root->query_pathkeys,
|
||||
list_length(orderbyclauses));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3051,24 +3057,24 @@ expand_indexqual_rowcompare(PlannerInfo *root,
|
||||
|
||||
/*
|
||||
* match_pathkeys_to_index
|
||||
* Test whether an index can produce output ordered according to the
|
||||
* given pathkeys using "ordering operators".
|
||||
* For the given 'index' and 'pathkeys', output a list of suitable ORDER
|
||||
* BY expressions, each of the form "indexedcol operator pseudoconstant",
|
||||
* along with an integer list of the index column numbers (zero based)
|
||||
* that each clause would be used with.
|
||||
*
|
||||
* If it can, return a list of suitable ORDER BY expressions, each of the form
|
||||
* "indexedcol operator pseudoconstant", along with an integer list of the
|
||||
* index column numbers (zero based) that each clause would be used with.
|
||||
* NIL lists are returned if the ordering is not achievable this way.
|
||||
*
|
||||
* On success, the result list is ordered by pathkeys, and in fact is
|
||||
* one-to-one with the requested pathkeys.
|
||||
* This attempts to find an ORDER BY and index column number for all items in
|
||||
* the pathkey list, however, if we're unable to match any given pathkey to an
|
||||
* index column, we return just the ones matched by the function so far. This
|
||||
* allows callers who are interested in partial matches to get them. Callers
|
||||
* can determine a partial match vs a full match by checking the outputted
|
||||
* list lengths. A full match will have one item in the output lists for each
|
||||
* item in the given 'pathkeys' list.
|
||||
*/
|
||||
static void
|
||||
match_pathkeys_to_index(IndexOptInfo *index, List *pathkeys,
|
||||
List **orderby_clauses_p,
|
||||
List **clause_columns_p)
|
||||
{
|
||||
List *orderby_clauses = NIL;
|
||||
List *clause_columns = NIL;
|
||||
ListCell *lc1;
|
||||
|
||||
*orderby_clauses_p = NIL; /* set default results */
|
||||
@@ -3084,10 +3090,6 @@ match_pathkeys_to_index(IndexOptInfo *index, List *pathkeys,
|
||||
bool found = false;
|
||||
ListCell *lc2;
|
||||
|
||||
/*
|
||||
* Note: for any failure to match, we just return NIL immediately.
|
||||
* There is no value in matching just some of the pathkeys.
|
||||
*/
|
||||
|
||||
/* Pathkey must request default sort order for the target opfamily */
|
||||
if (pathkey->pk_strategy != BTLessStrategyNumber ||
|
||||
@@ -3133,8 +3135,8 @@ match_pathkeys_to_index(IndexOptInfo *index, List *pathkeys,
|
||||
pathkey->pk_opfamily);
|
||||
if (expr)
|
||||
{
|
||||
orderby_clauses = lappend(orderby_clauses, expr);
|
||||
clause_columns = lappend_int(clause_columns, indexcol);
|
||||
*orderby_clauses_p = lappend(*orderby_clauses_p, expr);
|
||||
*clause_columns_p = lappend_int(*clause_columns_p, indexcol);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -3144,12 +3146,13 @@ match_pathkeys_to_index(IndexOptInfo *index, List *pathkeys,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) /* fail if no match for this pathkey */
|
||||
/*
|
||||
* Return the matches found so far when this pathkey couldn't be
|
||||
* matched to the index.
|
||||
*/
|
||||
if (!found)
|
||||
return;
|
||||
}
|
||||
|
||||
*orderby_clauses_p = orderby_clauses; /* success! */
|
||||
*clause_columns_p = clause_columns;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user