Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitc0b5fac

Browse files
committed
Simplify and speed up mapping of index opfamilies to pathkeys.
Formerly we looked up the operators associated with each index (cachingthem in relcache) and then the planner looked up the btree opfamilycontaining such operators in order to build the btree-centric pathkeyrepresentation that describes the index's sort order. This is quitepointless for btree indexes: we might as well just use the index's opfamilyinformation directly. That saves syscache lookup cycles during planning,and furthermore allows us to eliminate the relcache's caching of operatorsaltogether, which may help in reducing backend startup time.I added code to plancat.c to perform the same type of double lookupon-the-fly if it's ever faced with a non-btree amcanorder index AM.If such a thing actually becomes interesting for production, we shouldreplace that logic with some more-direct method for identifying thecorresponding btree opfamily; but it's not worth spending effort on now.There is considerably more to do pursuant to my recent proposal to get ridof sort-operator-based representations of sort orderings, but this patchgrabs some of the low-hanging fruit. I'll look at the remainder of thatwork after the current commitfest.
1 parent3c42efc commitc0b5fac

File tree

7 files changed

+217
-258
lines changed

7 files changed

+217
-258
lines changed

‎src/backend/optimizer/path/indxpath.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
380380
* how many of them are actually useful for this query. This is not
381381
* relevant unless we are at top level.
382382
*/
383-
index_is_ordered=OidIsValid(index->fwdsortop[0]);
383+
index_is_ordered= (index->sortopfamily!=NULL);
384384
if (index_is_ordered&&possibly_useful_pathkeys&&
385385
istoplevel&&outer_rel==NULL)
386386
{

‎src/backend/optimizer/path/pathkeys.c

Lines changed: 81 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,6 @@ static PathKey *make_canonical_pathkey(PlannerInfo *root,
3636
EquivalenceClass*eclass,Oidopfamily,
3737
intstrategy,boolnulls_first);
3838
staticboolpathkey_is_redundant(PathKey*new_pathkey,List*pathkeys);
39-
staticPathKey*make_pathkey_from_sortinfo(PlannerInfo*root,
40-
Expr*expr,Oidordering_op,
41-
boolnulls_first,
42-
Indexsortref,
43-
boolcreate_it,
44-
boolcanonicalize);
4539
staticVar*find_indexkey_var(PlannerInfo*root,RelOptInfo*rel,
4640
AttrNumbervarattno);
4741
staticboolright_merge_direction(PlannerInfo*root,PathKey*pathkey);
@@ -224,9 +218,9 @@ canonicalize_pathkeys(PlannerInfo *root, List *pathkeys)
224218

225219
/*
226220
* make_pathkey_from_sortinfo
227-
* Given an expression, a sortop,anda nulls-first flag, create
228-
*a PathKey.If canonicalize = true, the result is a "canonical"
229-
*PathKey,otherwise not. (But note it might be redundant anyway.)
221+
* Given an expressionandsort-order information, create a PathKey.
222+
* If canonicalize = true, the result is a "canonical" PathKey,
223+
* otherwise not. (But note it might be redundant anyway.)
230224
*
231225
* If the PathKey is being generated from a SortGroupClause, sortref should be
232226
* the SortGroupClause's SortGroupRef; otherwise zero.
@@ -240,46 +234,39 @@ canonicalize_pathkeys(PlannerInfo *root, List *pathkeys)
240234
*/
241235
staticPathKey*
242236
make_pathkey_from_sortinfo(PlannerInfo*root,
243-
Expr*expr,Oidordering_op,
237+
Expr*expr,
238+
Oidopfamily,
239+
Oidopcintype,
240+
boolreverse_sort,
244241
boolnulls_first,
245242
Indexsortref,
246243
boolcreate_it,
247244
boolcanonicalize)
248245
{
249-
Oidopfamily,
250-
opcintype;
251246
int16strategy;
252247
Oidequality_op;
253248
List*opfamilies;
254249
EquivalenceClass*eclass;
255250

251+
strategy=reverse_sort ?BTGreaterStrategyNumber :BTLessStrategyNumber;
252+
256253
/*
257-
* An ordering operator fully determines the behavior of its opfamily, so
258-
* could only meaningfully appear in one family --- or perhaps two if one
259-
* builds a reverse-sort opfamily, but there's not much point in that
260-
* anymore. But EquivalenceClasses need to contain opfamily lists based
261-
* on the family membership of equality operators, which could easily be
262-
* bigger.So, look up the equality operator that goes with the ordering
263-
* operator (this should be unique) and get its membership.
254+
* EquivalenceClasses need to contain opfamily lists based on the family
255+
* membership of mergejoinable equality operators, which could belong to
256+
* more than one opfamily. So we have to look up the opfamily's equality
257+
* operator and get its membership.
264258
*/
265-
266-
/* Find the operator in pg_amop --- failure shouldn't happen */
267-
if (!get_ordering_op_properties(ordering_op,
268-
&opfamily,&opcintype,&strategy))
269-
elog(ERROR,"operator %u is not a valid ordering operator",
270-
ordering_op);
271-
/* Get matching equality operator */
272259
equality_op=get_opfamily_member(opfamily,
273260
opcintype,
274261
opcintype,
275262
BTEqualStrategyNumber);
276263
if (!OidIsValid(equality_op))/* shouldn't happen */
277-
elog(ERROR,"could not find equality operator forordering operator %u",
278-
ordering_op);
264+
elog(ERROR,"could not find equality operator foropfamily %u",
265+
opfamily);
279266
opfamilies=get_mergejoin_opfamilies(equality_op);
280267
if (!opfamilies)/* certainly should find some */
281-
elog(ERROR,"could not find opfamilies forordering operator %u",
282-
ordering_op);
268+
elog(ERROR,"could not find opfamilies forequality operator %u",
269+
equality_op);
283270

284271
/*
285272
* When dealing with binary-compatible opclasses, we have to ensure that
@@ -322,6 +309,42 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
322309
returnmakePathKey(eclass,opfamily,strategy,nulls_first);
323310
}
324311

312+
/*
313+
* make_pathkey_from_sortop
314+
* Like make_pathkey_from_sortinfo, but work from a sort operator.
315+
*
316+
* This should eventually go away, but we need to restructure SortGroupClause
317+
* first.
318+
*/
319+
staticPathKey*
320+
make_pathkey_from_sortop(PlannerInfo*root,
321+
Expr*expr,
322+
Oidordering_op,
323+
boolnulls_first,
324+
Indexsortref,
325+
boolcreate_it,
326+
boolcanonicalize)
327+
{
328+
Oidopfamily,
329+
opcintype;
330+
int16strategy;
331+
332+
/* Find the operator in pg_amop --- failure shouldn't happen */
333+
if (!get_ordering_op_properties(ordering_op,
334+
&opfamily,&opcintype,&strategy))
335+
elog(ERROR,"operator %u is not a valid ordering operator",
336+
ordering_op);
337+
returnmake_pathkey_from_sortinfo(root,
338+
expr,
339+
opfamily,
340+
opcintype,
341+
(strategy==BTGreaterStrategyNumber),
342+
nulls_first,
343+
sortref,
344+
create_it,
345+
canonicalize);
346+
}
347+
325348

326349
/****************************************************************************
327350
*PATHKEY COMPARISONS
@@ -479,11 +502,10 @@ get_cheapest_fractional_path_for_pathkeys(List *paths,
479502
* build_index_pathkeys
480503
* Build a pathkeys list that describes the ordering induced by an index
481504
* scan using the given index. (Note that an unordered index doesn't
482-
* induce any ordering; such an index will have no sortop OIDS in
483-
* its sortops arrays, and we will return NIL.)
505+
* induce any ordering, so we return NIL.)
484506
*
485-
* If 'scandir' is BackwardScanDirection,attempt tobuild pathkeys
486-
*representing abackwards scan of the index.Return NIL if can't do it.
507+
* If 'scandir' is BackwardScanDirection, build pathkeys representing a
508+
* backwards scan of the index.
487509
*
488510
* The result is canonical, meaning that redundant pathkeys are removed;
489511
* it may therefore have fewer entries than there are index columns.
@@ -500,31 +522,32 @@ build_index_pathkeys(PlannerInfo *root,
500522
ScanDirectionscandir)
501523
{
502524
List*retval=NIL;
503-
ListCell*indexprs_item=list_head(index->indexprs);
525+
ListCell*indexprs_item;
504526
inti;
505527

528+
if (index->sortopfamily==NULL)
529+
returnNIL;/* non-orderable index */
530+
531+
indexprs_item=list_head(index->indexprs);
506532
for (i=0;i<index->ncolumns;i++)
507533
{
508-
Oidsortop;
534+
boolreverse_sort;
509535
boolnulls_first;
510536
intikey;
511537
Expr*indexkey;
512538
PathKey*cpathkey;
513539

514540
if (ScanDirectionIsBackward(scandir))
515541
{
516-
sortop=index->revsortop[i];
542+
reverse_sort=!index->reverse_sort[i];
517543
nulls_first= !index->nulls_first[i];
518544
}
519545
else
520546
{
521-
sortop=index->fwdsortop[i];
547+
reverse_sort=index->reverse_sort[i];
522548
nulls_first=index->nulls_first[i];
523549
}
524550

525-
if (!OidIsValid(sortop))
526-
break;/* no more orderable columns */
527-
528551
ikey=index->indexkeys[i];
529552
if (ikey!=0)
530553
{
@@ -543,7 +566,9 @@ build_index_pathkeys(PlannerInfo *root,
543566
/* OK, try to make a canonical pathkey for this sort key */
544567
cpathkey=make_pathkey_from_sortinfo(root,
545568
indexkey,
546-
sortop,
569+
index->sortopfamily[i],
570+
index->opcintype[i],
571+
reverse_sort,
547572
nulls_first,
548573
0,
549574
false,
@@ -892,13 +917,13 @@ make_pathkeys_for_sortclauses(PlannerInfo *root,
892917

893918
sortkey= (Expr*)get_sortgroupclause_expr(sortcl,tlist);
894919
Assert(OidIsValid(sortcl->sortop));
895-
pathkey=make_pathkey_from_sortinfo(root,
896-
sortkey,
897-
sortcl->sortop,
898-
sortcl->nulls_first,
899-
sortcl->tleSortGroupRef,
900-
true,
901-
canonicalize);
920+
pathkey=make_pathkey_from_sortop(root,
921+
sortkey,
922+
sortcl->sortop,
923+
sortcl->nulls_first,
924+
sortcl->tleSortGroupRef,
925+
true,
926+
canonicalize);
902927

903928
/* Canonical form eliminates redundant ordering keys */
904929
if (canonicalize)
@@ -935,13 +960,13 @@ make_pathkeys_for_aggregate(PlannerInfo *root,
935960
* We arbitrarily set nulls_first to false. Actually, a MIN/MAX agg can
936961
* use either nulls ordering option, but that is dealt with elsewhere.
937962
*/
938-
pathkey=make_pathkey_from_sortinfo(root,
939-
aggtarget,
940-
aggsortop,
941-
false,/* nulls_first */
942-
0,
943-
true,
944-
false);
963+
pathkey=make_pathkey_from_sortop(root,
964+
aggtarget,
965+
aggsortop,
966+
false,/* nulls_first */
967+
0,
968+
true,
969+
false);
945970
returnlist_make1(pathkey);
946971
}
947972

‎src/backend/optimizer/util/plancat.c

Lines changed: 72 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -189,19 +189,9 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
189189
RelationGetForm(indexRelation)->reltablespace;
190190
info->rel=rel;
191191
info->ncolumns=ncolumns=index->indnatts;
192-
193-
/*
194-
* Allocate per-column info arrays. To save a few palloc cycles
195-
* we allocate all the Oid-type arrays in one request. We must
196-
* pre-zero the sortop and nulls_first arrays in case the index is
197-
* unordered.
198-
*/
199192
info->indexkeys= (int*)palloc(sizeof(int)*ncolumns);
200-
info->opfamily= (Oid*)palloc0(sizeof(Oid)* (4*ncolumns));
201-
info->opcintype=info->opfamily+ncolumns;
202-
info->fwdsortop=info->opcintype+ncolumns;
203-
info->revsortop=info->fwdsortop+ncolumns;
204-
info->nulls_first= (bool*)palloc0(sizeof(bool)*ncolumns);
193+
info->opfamily= (Oid*)palloc(sizeof(Oid)*ncolumns);
194+
info->opcintype= (Oid*)palloc(sizeof(Oid)*ncolumns);
205195

206196
for (i=0;i<ncolumns;i++)
207197
{
@@ -219,49 +209,90 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
219209
info->amhasgetbitmap=OidIsValid(indexRelation->rd_am->amgetbitmap);
220210

221211
/*
222-
* Fetch the ordering operators associated with the index, if any.
223-
* We expect that all ordering-capable indexes use btree's
224-
* strategy numbers for the ordering operators.
212+
* Fetch the ordering information for the index, if any.
225213
*/
226-
if (indexRelation->rd_am->amcanorder)
214+
if (info->relam==BTREE_AM_OID)
227215
{
228-
intnstrat=indexRelation->rd_am->amstrategies;
216+
/*
217+
* If it's a btree index, we can use its opfamily OIDs
218+
* directly as the sort ordering opfamily OIDs.
219+
*/
220+
Assert(indexRelation->rd_am->amcanorder);
221+
222+
info->sortopfamily=info->opfamily;
223+
info->reverse_sort= (bool*)palloc(sizeof(bool)*ncolumns);
224+
info->nulls_first= (bool*)palloc(sizeof(bool)*ncolumns);
229225

230226
for (i=0;i<ncolumns;i++)
231227
{
232228
int16opt=indexRelation->rd_indoption[i];
233-
intfwdstrat;
234-
intrevstrat;
235229

236-
if (opt&INDOPTION_DESC)
237-
{
238-
fwdstrat=BTGreaterStrategyNumber;
239-
revstrat=BTLessStrategyNumber;
240-
}
241-
else
242-
{
243-
fwdstrat=BTLessStrategyNumber;
244-
revstrat=BTGreaterStrategyNumber;
245-
}
230+
info->reverse_sort[i]= (opt&INDOPTION_DESC)!=0;
231+
info->nulls_first[i]= (opt&INDOPTION_NULLS_FIRST)!=0;
232+
}
233+
}
234+
elseif (indexRelation->rd_am->amcanorder)
235+
{
236+
/*
237+
* Otherwise, identify the corresponding btree opfamilies by
238+
* trying to map this index's "<" operators into btree. Since
239+
* "<" uniquely defines the behavior of a sort order, this is
240+
* a sufficient test.
241+
*
242+
* XXX This method is rather slow and also requires the
243+
* undesirable assumption that the other index AM numbers its
244+
* strategies the same as btree. It'd be better to have a way
245+
* to explicitly declare the corresponding btree opfamily for
246+
* each opfamily of the other index type. But given the lack
247+
* of current or foreseeable amcanorder index types, it's not
248+
* worth expending more effort on now.
249+
*/
250+
info->sortopfamily= (Oid*)palloc(sizeof(Oid)*ncolumns);
251+
info->reverse_sort= (bool*)palloc(sizeof(bool)*ncolumns);
252+
info->nulls_first= (bool*)palloc(sizeof(bool)*ncolumns);
253+
254+
for (i=0;i<ncolumns;i++)
255+
{
256+
int16opt=indexRelation->rd_indoption[i];
257+
Oidltopr;
258+
Oidbtopfamily;
259+
Oidbtopcintype;
260+
int16btstrategy;
246261

247-
/*
248-
* Index AM must have a fixed set of strategies for it to
249-
* make sense to specify amcanorder, so we need not allow
250-
* the case amstrategies == 0.
251-
*/
252-
if (fwdstrat>0)
262+
info->reverse_sort[i]= (opt&INDOPTION_DESC)!=0;
263+
info->nulls_first[i]= (opt&INDOPTION_NULLS_FIRST)!=0;
264+
265+
ltopr=get_opfamily_member(info->opfamily[i],
266+
info->opcintype[i],
267+
info->opcintype[i],
268+
BTLessStrategyNumber);
269+
if (OidIsValid(ltopr)&&
270+
get_ordering_op_properties(ltopr,
271+
&btopfamily,
272+
&btopcintype,
273+
&btstrategy)&&
274+
btopcintype==info->opcintype[i]&&
275+
btstrategy==BTLessStrategyNumber)
253276
{
254-
Assert(fwdstrat <=nstrat);
255-
info->fwdsortop[i]=indexRelation->rd_operator[i*nstrat+fwdstrat-1];
277+
/* Successful mapping */
278+
info->sortopfamily[i]=btopfamily;
256279
}
257-
if (revstrat>0)
280+
else
258281
{
259-
Assert(revstrat <=nstrat);
260-
info->revsortop[i]=indexRelation->rd_operator[i*nstrat+revstrat-1];
282+
/* Fail ... quietly treat index as unordered */
283+
info->sortopfamily=NULL;
284+
info->reverse_sort=NULL;
285+
info->nulls_first=NULL;
286+
break;
261287
}
262-
info->nulls_first[i]= (opt&INDOPTION_NULLS_FIRST)!=0;
263288
}
264289
}
290+
else
291+
{
292+
info->sortopfamily=NULL;
293+
info->reverse_sort=NULL;
294+
info->nulls_first=NULL;
295+
}
265296

266297
/*
267298
* Fetch the index expressions and predicate, if any. We must

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp