GISTSTATE is too large

From: Andres Freund <andres(at)anarazel(dot)de>
To: pgsql-hackers(at)postgresql(dot)org
Subject: GISTSTATE is too large
Date: 2021-04-25 22:20:53
Message-ID: 20210425222053.y6vcdiqohdoshi26@alap3.anarazel.de
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

On twitter it was mentioned [1] that gist index builds spend a lot of time
in FunctionCall3Coll. Which could be addressed to a good degree by not
using FunctionCall3Coll() which needs to call InitFunctionCallInfoData()
every time, but instead doing so once by including the FunctionCallInfo
in GISTSTATE.

Which made me look at GISTSTATEs layout. And, uh, I was a bit shocked:
struct GISTSTATE {
MemoryContext scanCxt; /* 0 8 */
MemoryContext tempCxt; /* 8 8 */
TupleDesc leafTupdesc; /* 16 8 */
TupleDesc nonLeafTupdesc; /* 24 8 */
TupleDesc fetchTupdesc; /* 32 8 */
FmgrInfo consistentFn[32]; /* 40 1536 */
/* --- cacheline 24 boundary (1536 bytes) was 40 bytes ago --- */
FmgrInfo unionFn[32]; /* 1576 1536 */
...
/* --- cacheline 216 boundary (13824 bytes) was 40 bytes ago --- */
Oid supportCollation[32]; /* 13864 128 */

/* size: 13992, cachelines: 219, members: 15 */
/* last cacheline: 40 bytes */
};

So the basic GISTSTATE is 14kB large. And all the information needed to
call support functions for one attribute is spaced so far appart that
it's guaranteed to be on different cachelines and to be very unlikely to
be prefetched by the hardware prefetcher.

It seems pretty clear that this should be changed to be something more
like

typedef struct GIST_COL_STATE
{
FmgrInfo consistentFn;
FmgrInfo unionFn;
FmgrInfo compressFn;
FmgrInfo decompressFn;
FmgrInfo penaltyFn;
FmgrInfo picksplitFn;
FmgrInfo equalFn;
FmgrInfo distanceFn;
FmgrInfo fetchFn;

/* Collations to pass to the support functions */
Oid supportCollation;
} GIST_COL_STATE;

typedef struct GISTSTATE
{
MemoryContext scanCxt; /* context for scan-lifespan data */
MemoryContext tempCxt; /* short-term context for calling functions */

TupleDesc leafTupdesc; /* index's tuple descriptor */
TupleDesc nonLeafTupdesc; /* truncated tuple descriptor for non-leaf
* pages */
TupleDesc fetchTupdesc; /* tuple descriptor for tuples returned in an
* index-only scan */

GIST_COL_STATE column_state[FLEXIBLE_ARRAY_MEMBER];
}

with initGISTstate allocating based on
IndexRelationGetNumberOfKeyAttributes() instead of using a constant.

And then subsequently change GIST_COL_STATE to embed the
FunctionCallInfo, rather than initializiing them on the stack for every
call.

I'm not planning on doing this work, but I thought it's sensible to send
to the list anyway.

Greetings,

Andres Freund

[1] https://twitter.com/komzpa/status/1386420422225240065

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Masahiko Sawada 2021-04-26 00:32:22 Re: decoupling table and index vacuum
Previous Message Alvaro Herrera 2021-04-25 19:40:40 Re: Fix dropped object handling in pg_event_trigger_ddl_commands