Fixes #27158: ingestion slowdown from tag_usage seq-scan on Postgres#27745
Fixes #27158: ingestion slowdown from tag_usage seq-scan on Postgres#27745sonika-shah wants to merge 4 commits intomainfrom
Conversation
6243f22 to
5e01f10
Compare
There was a problem hiding this comment.
Pull request overview
Restores efficient Postgres execution for tag_usage prefix-LIKE lookups by reintroducing a usable index for the current query shape and removing the brittle coupling between query predicates and partial index predicates.
Changes:
- Add a non-partial btree index on
tag_usage.targetfqnhash_lowerusingtext_pattern_opsto serve prefixLIKEqueries. - Rebuild the existing
tag_usagepartial indexes (previouslyWHERE state = 1) as non-partial indexes to avoid future predicate-coupling regressions. - Rebuild the existing
gin_tag_usage_targetfqn_trgmindex without the partial predicate.
The 1.11.0 perf migration (#23054) added four `WHERE state = 1` partial indexes on tag_usage; #24063 dropped the matching `state = 1` predicate from getTagsInternalByPrefix (Suggested-state rows are valid for both classification and glossary derivation), leaving every partial index inapplicable. Postgres fell back to a parallel seq scan; MySQL was unaffected because its 1.11.0 indexes were never partial. Adds a non-partial single-col btree on targetfqnhash_lower (mirrors MySQL's idx_targetfqnhash_lower) and rebuilds the four partials as non-partial -- same shape, same INCLUDE columns, predicate coupling removed so future query changes can't silently invalidate them. Verified end-to-end against a local Postgres with 50k rows: seq scan reproduced before the fix (matches reporter's EXPLAIN), bitmap index scan after, both for inline and prepared-statement paths.
9520cc4 to
bc73c29
Compare
🟡 Playwright Results — all passed (14 flaky)✅ 3984 passed · ❌ 0 failed · 🟡 14 flaky · ⏭️ 86 skipped
🟡 14 flaky test(s) (passed on retry)
How to debug locally# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip # view trace |
Ship the fix in the 1.12.7 release line so customers on 1.12.x get it without waiting for 2.0.x. Also closes the second structural gap with MySQL: a non-partial single-col btree on tagfqn_lower mirroring MySQL's idx_tagfqn_lower (1.11.0). 1.12.8 directory removed; 1.12.7's existing schemaChanges.sql now carries the tag_usage indexes alongside the entity_extension migration. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
If CREATE INDEX CONCURRENTLY fails partway (lock timeout, OOM, connection drop on a busy multi-GB tag_usage), Postgres leaves the index in an INVALID state. A subsequent CREATE ... IF NOT EXISTS sees the catalog row and silently skips, leaving the index permanently broken while the migration reports success. The four composite indexes already use the DROP-then-CREATE pattern; applying the same to the two new single-col indexes for symmetry. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Fixes #27158: restore tag_usage prefix-LIKE index on Postgres The 1.11.0 perf migration (#23054) added four `WHERE state = 1` partial indexes on tag_usage; #24063 dropped the matching `state = 1` predicate from getTagsInternalByPrefix (Suggested-state rows are valid for both classification and glossary derivation), leaving every partial index inapplicable. Postgres fell back to a parallel seq scan; MySQL was unaffected because its 1.11.0 indexes were never partial. Adds non-partial single-col btrees on targetfqnhash_lower and tagfqn_lower (mirror MySQL's idx_targetfqnhash_lower / idx_tagfqn_lower) and rebuilds the four partials as non-partial -- same shape, same INCLUDE columns, predicate coupling removed so future query changes can't silently invalidate them. Backport of #27745 (main) onto the 1.12.7 release line so customers on 1.12.x get the fix without waiting for 2.0.x. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Drop new indexes before CREATE to defuse failed-CONCURRENTLY edge case If CREATE INDEX CONCURRENTLY fails partway (lock timeout, OOM, connection drop on a busy multi-GB tag_usage), Postgres leaves the index in an INVALID state. A subsequent CREATE ... IF NOT EXISTS sees the catalog row and silently skips, leaving the index permanently broken while the migration reports success. The four composite indexes already use the DROP-then-CREATE pattern; applying the same to the two new single-col indexes for symmetry. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Code Review ✅ Approved 2 resolved / 2 findingsAdds a GIN trigram index on the tag_usage column to resolve ingestion slowdowns caused by sequential scans. This change addresses previously identified index targeting and privilege concerns. ✅ 2 resolved✅ Performance: GIN trigram index targets wrong column for the slow query
✅ Edge Case: CREATE EXTENSION pg_trgm may fail without superuser privileges
OptionsDisplay: compact → Showing less information. Comment with these commands to change:
Was this helpful? React with 👍 / 👎 | Gitar |
Fixes #27158
Summary
getTagsInternalByPrefixparallel seq-scanstag_usageon Postgres, causing RDS CPU spikes during ingestion.Cause: 1.11.0 (#23054) added four partial indexes on
tag_usagefilteredWHERE state = 1. #24063 then dropped the matchingstate = 1filter from the query (Suggested rows are valid for both classification and glossary derivation), leaving every partial index inapplicable. MySQL was unaffected — its 1.11.0 indexes were never partial (no partial-index syntax).Fix
bootstrap/sql/migrations/native/1.12.7/postgres/schemaChanges.sql:targetfqnhash_lowerandtagfqn_lower— mirrors MySQL'sidx_targetfqnhash_lower/idx_tagfqn_lowerfrom 1.11.0.WHERE state = 1removed so future predicate changes can't silently invalidate them.All DDL is
CONCURRENTLYand idempotent. No Java/query change. No MySQL change needed.Verification
50k synthetic rows in local Postgres:
Seq Scan(Rows Removed by Filter: 49010)Bitmap Index Scan on idx_tag_usage_targetfqnhash_lower_patternLIKE LOWER($1)→ range scanTest plan
Summary by Gitar
gin_tag_usage_targetfqn_trgmusingpg_trgmextension for optimized pattern searching.pg_trgmextension on the database to support new GIN indexing.description-sanitizerthat was not mentioned in the description.This will update automatically on new commits.