Repository navigation
Document indexing the Postgres projections table - #132
Open
jonassvalin wants to merge 4 commits into
Open
jonassvalin wants to merge 4 commits into
jonassvalin wants to merge 4 commits into
Conversation
Add a README section on which index expressions match the store's queries, why partial expression indexes leave the planner without statistics, the recommended composite and partitioned alternatives, and how prepared statements interact with the current rendering, plus a changelog fragment.
The library doesn't ship or test a partitioned projections schema, so recommending one is premature.
8 of 10 tasks
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an "Indexing Projections in Postgres" section to the README. It explains which index expressions match the SQL the projection store renders, why partial expression indexes mislead the planner, the recommended alternatives, and how prepared statements interact with the current rendering. Docs only; no code changes. Partitioning the table by
nameis deliberately left out, because the library doesn't ship or test a partitioned schema.This is the first of four PRs from the included plan. PRs 2–4 change how the Postgres converters render path keys, the projection
nameand jsonb values. Each can be accepted or declined on its own. This one describes behaviour that holds today, whatever happens to the others, and is meant to start the discussion.Motivation
A downstream service had list queries with a ~700ms floor in production (2–3.8s locally). All its expression indexes were partial (
WHERE name = '…'), and Postgres doesn't use a partial index's statistics when estimating selectivity. So every equality filter was estimated at a fixed 0.5%, and the planner walked the wrong index. Non-partial indexes that lead withnamefixed it. Nothing in the library's docs says how to index the sharedprojectionstable, or that index expressions must match the renderedjsonb_extract_path(state, …)form exactly.Changes
Key Changes
name, builtCONCURRENTLY;jsonb_extract_pathand which renderjsonb_extract_path_text;jsonb_path_opsforCONTAINSon larger values;nameare bound today, so generic plans can't use these indexes. Workarounds areplan_cache_mode = force_custom_planor a pool withprepare_threshold=None;CREATE STATISTICSmemory use duringANALYZEon largestatedocuments.Sources for the Postgres behaviour
examine_variableinsrc/backend/utils/adt/selfuncs.cignores indexes with a predicate.DEFAULT_EQ_SEL(0.005) andDEFAULT_INEQ_SEL(1/3) insrc/include/utils/selfuncs.h.Breaking Changes
None.
Migration Guide
None needed.
How to Verify
Automated Verification
mise run docs:buildmise run test:unit(1747)mise run types:checkmise run lint:checkmise run format:checkManual Verification
Checked every claim against Postgres 16.3, with 200,000 rows split across two projection names:
(name, expression)index, the estimate was 59,954.EXPLAIN (GENERIC_PLAN)): with the path key bound, no expression index is used; with a literal key, the composite index is. Withnamebound, a partial index isn't used; with a literalname, it is._textand GIN indexes: ajsonb_extract_path_textindex matchesIS NULL, and a GINjsonb_path_opsindex matches@>.index row size 7216 exceeds btree version 4 maximum 2704.sql/create_projections_table.sqlplussql/create_projections_indices.sql, and the Python snippet's imports resolve.The
ANALYZEmemory caution comes from the downstream investigation and is stated without version specifics. I haven't verified it independently.Checklist
Related Issues
None. The implementation plan for all four PRs and its review are included under
meta/plans/andmeta/reviews/plans/.