perf(pglite): purge unused tags with NOT EXISTS instead of NOT IN

On a 97k-track library the tag purge in the scanner GC ran for many
minutes: PostgreSQL re-evaluates a NOT IN subquery of ~1M tag references
per tag row. A materialized set with NOT EXISTS takes 1.4 s locally
versus 55 s for NOT IN at that scale; work_mem made no difference.
This commit is contained in:
Deluan 2026-09-04 22:36:13 -04:00
commit ec37e23718

View file

@ -82,16 +82,20 @@ func (r *tagRepository) GetAll(name model.TagName, options ...model.QueryOptions
}
func (r *tagRepository) purgeUnused() error {
// NOT EXISTS over a materialized set: NOT IN re-scans the ~1M-row subquery per tag (40x slower).
del := Delete(r.tableName).Where(`
id not in (select elem->>'id'
from album
cross join lateral jsonb_each(coalesce(album.tags, '{}'::jsonb)) as e(k, arr)
cross join lateral jsonb_array_elements(e.arr) as elem
UNION
select elem->>'id'
from media_file
cross join lateral jsonb_each(coalesce(media_file.tags, '{}'::jsonb)) as e(k, arr)
cross join lateral jsonb_array_elements(e.arr) as elem)
not exists (
with used(id) as materialized (
select elem->>'id'
from album
cross join lateral jsonb_each(coalesce(album.tags, '{}'::jsonb)) as e(k, arr)
cross join lateral jsonb_array_elements(e.arr) as elem
union
select elem->>'id'
from media_file
cross join lateral jsonb_each(coalesce(media_file.tags, '{}'::jsonb)) as e(k, arr)
cross join lateral jsonb_array_elements(e.arr) as elem)
select 1 from used where used.id = ` + r.tableName + `.id)
`)
c, err := r.executeSQL(del)
if err != nil {