From 943beae2783242927bd313f1d2cceb8a9174838b Mon Sep 17 00:00:00 2001 From: Deluan Date: Sat, 5 Sep 2026 03:54:12 -0400 Subject: [PATCH] perf(pglite): filter artist roles by jsonb containment After the post-scan ANALYZE the planner probed library_artist once per artist for the role filter written as stats->'role'->>'m' IS NOT NULL: 29,602 lookups at 3.8 ms each, 116 s for the artist list on roy. The containment form (stats @> '{"role": {}}') is served by the GIN index: 0.2 s for the same list. --- persistence/artist_repository.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/persistence/artist_repository.go b/persistence/artist_repository.go index 706a9738f..3be42a44b 100644 --- a/persistence/artist_repository.go +++ b/persistence/artist_repository.go @@ -163,7 +163,8 @@ func NewArtistRepository(ctx context.Context, db dbx.Builder) model.ArtistReposi func roleFilter(_ string, role any) Sqlizer { if role, ok := role.(string); ok { if _, ok := model.AllRoles[role]; ok { - return Expr("library_artist.stats->'" + role + "'->>'m' IS NOT NULL") + // Containment is served by the GIN index on stats; the ->> form forces a row-by-row probe. + return Expr("library_artist.stats @> ?::jsonb", `{"`+role+`": {}}`) } } return Eq{"1": 2}