perf: replace LATERAL jsonb_each_text label queries with indexed lookup - #2515
Closed
rh-jfuller wants to merge 1 commit into
Closed
perf: replace LATERAL jsonb_each_text label queries with indexed lookup#2515rh-jfuller wants to merge 1 commit into
rh-jfuller wants to merge 1 commit into
Conversation
…up tables The fetch_labels query scanned every row in advisory/sbom, expanded each row's JSONB labels column via LATERAL jsonb_each_text(), then applied ILIKE filtering on the expanded text. No index could accelerate this pattern. Add denormalized advisory_label and sbom_label tables that store one row per key/value pair with a pre-computed key_value text column. GIN trigram indexes on key_value enable fast ILIKE substring matching. Triggers on the source tables keep the lookup tables in sync automatically on INSERT, UPDATE, and DELETE. Rewrite the fetch_labels query to read from the new tables instead of performing runtime JSONB expansion.
Contributor
Reviewer's GuideReplaces expensive LATERAL jsonb_each_text-based label searching with denormalized label lookup tables backed by trigram indexes, and wires them into the application and migration system for performant ILIKE substring searches. Sequence diagram for fetch_labels using denormalized label lookup tablessequenceDiagram
participant Service
participant Database
participant advisory_label_kv_trgm_idx
participant sbom_label_kv_trgm_idx
Service->>Database: fetch_labels(type, pattern)
alt [DocumentType.Advisory]
Database->>Database: SELECT DISTINCT ON (key, value) FROM advisory_label WHERE key_value ILIKE pattern
Database->>advisory_label_kv_trgm_idx: use GIN gin_trgm_ops index on key_value
advisory_label_kv_trgm_idx-->>Database: matching rows
else [DocumentType.Sbom]
Database->>Database: SELECT DISTINCT ON (key, value) FROM sbom_label WHERE key_value ILIKE pattern
Database->>sbom_label_kv_trgm_idx: use GIN gin_trgm_ops index on key_value
sbom_label_kv_trgm_idx-->>Database: matching rows
end
Database-->>Service: Vec<serde_json::Value>
Entity relationship diagram for new label lookup tableserDiagram
advisory {
UUID id
JSONB labels
}
advisory_label {
UUID advisory_id
TEXT key
TEXT value
TEXT key_value
}
sbom {
UUID sbom_id
JSONB labels
}
sbom_label {
UUID sbom_id
TEXT key
TEXT value
TEXT key_value
}
advisory ||--o{ advisory_label : has_labels
sbom ||--o{ sbom_label : has_labels
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Contributor
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- If
labelscan ever be NULL on advisory/sbom, consider wrappingjsonb_each_text(NEW.labels)inCOALESCE(NEW.labels, '{}'::jsonb)in the trigger functions to avoid unexpected behavior when labels are absent. - Instead of manually maintaining
key_valuevia triggers and thelabel_key_valuehelper, consider definingkey_valueas a generated column (e.g.,GENERATED ALWAYS AS (...) STORED) to remove the risk of drift betweenkey/valueandkey_value.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- If `labels` can ever be NULL on advisory/sbom, consider wrapping `jsonb_each_text(NEW.labels)` in `COALESCE(NEW.labels, '{}'::jsonb)` in the trigger functions to avoid unexpected behavior when labels are absent.
- Instead of manually maintaining `key_value` via triggers and the `label_key_value` helper, consider defining `key_value` as a generated column (e.g., `GENERATED ALWAYS AS (...) STORED`) to remove the risk of drift between `key`/`value` and `key_value`.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
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.
The fetch_labels query scanned every row in advisory/sbom, expanded each row's JSONB labels column via LATERAL jsonb_each_text(), then applied ILIKE filtering on the expanded text. No index could accelerate this pattern.
The new query hits the GIN trigram index for ILIKE filtering and reads from a pre-expanded table — no more full-table JSONB expansion. The trigram index supports the existing substring matching behavior (e.g., searching "pd" still finds "spdx").
Addresses TC-5204
Summary by Sourcery
Introduce denormalized advisory and SBOM label lookup tables and update label fetching to use them for more efficient indexed searches.
New Features:
Enhancements: