Re: Parallel CREATE INDEX for GIN indexes
Tomas Vondra <tomas@vondra.me>
From: Tomas Vondra <tomas@vondra.me>
To: Matthias van de Meent <boekewurm+postgres@gmail.com>
Cc: Kirill Reshke <reshkekirill@gmail.com>,
Michael Paquier <michael@paquier.xyz>,
PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Date: 2025-02-26T20:08:39Z
Lists: pgsql-hackers
Attachments
- poc-gin-build-hashing.patch (text/x-patch) patch
While working on the progress reporting, I've been looking into the
performance results, particularly why the parallelism doesn't help much
for some indexes - e.g. the index on the headers JSONB column.
CREATE INDEX headers_jsonb_idx
ON messages USING gin (msg_headers);
In this case the parallelism helps only a little bit - serial build
takes ~47 seconds, parallel builds with 1 worker (so 2 with leader)
takes ~40 seconds. Not great.
There are two reasons for this. First, the "keys" (JSONB values) are
mostly unique, with only 1 or 2 TIDs per key, which means the workers
can't really do much merging. But shifting the merges to workers is the
main benefit of parallel builds - if the merge happens in the leader
anyway, this explains the lack of speedup.
The other reason is that with JSON keys the comparisons are rather
expensive, and we're comparing a lot of keys. It occurred to me we can
work around this by comparing hashes first, and comparing the full keys
only when the hashes match. And indeed, this helps a lot (there's a very
rough PoC patch attached) - I'm seeing ~20% speedup from this, so the
parallel build runs in ~30 seconds now. Still not quite serial speedup,
but better than before.
But I think this optimization is mostly orthogonal to parallel builds,
i.e. we could do the same thing for serial builds (while accumulating
data in memory, we could do these comparisons). But it needs to be
careful about still writing the data out in the "natural" order, not
ordered by hash. The hash randomizes the pattern, making it much less
efficient for bulk inserts (it trashes the buffers, etc.). The PoC patch
for parallel builds addresses this by ignoring the hash during the final
tuplesort, the serial builds would need to do something similar.
My conclusion is this can be left as a future improvement, independent
of the parallel builds.
regards
--
Tomas Vondra
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Exercise parallel GIN builds in regression tests
- f6e5d21bf73f 19 (unreleased) landed
- 32593394ee43 18.2 landed
-
Lookup the correct ordering for parallel GIN builds
- db14dcdec69d 19 (unreleased) landed
- eee71a66cc86 18.2 landed
-
Fix memory leak in _gin_parallel_merge
- 1681a70df3d6 18.0 landed
-
Enforce memory limit during parallel GIN builds
- b229c1016477 18.0 landed
-
Compress TID lists when writing GIN tuples to disk
- 0b2a45a5d1f2 18.0 landed
-
Allow parallel CREATE INDEX for GIN indexes
- 8492feb98f6d 18.0 landed