Created
April 18, 2026 19:31
-
-
Save Deeds67/f19041ac33a32b53b7fd08823bc7e5cf to your computer and use it in GitHub Desktop.
Gallery smart-search performance diagnostic — EXPLAIN ANALYZE on fork's OR-EXISTS vs upstream vs candidate UNION-CTE fix
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
| -- Gallery smart-search performance diagnostic | |
| -- | |
| -- How to run: | |
| -- 1. Find your postgres container: docker ps | grep postgres | |
| -- 2. Run (adjust container name, DB user, DB name as needed): | |
| -- docker exec -i <your-postgres-container> psql -U postgres -d immich -XAt < this-file.sql | |
| -- Or interactively: | |
| -- docker exec -it <your-postgres-container> psql -U postgres -d immich | |
| -- ...then paste the SQL below. | |
| -- | |
| -- Only run on Gallery. Immich doesn't have shared_space tables, so queries 5 and 6 will fail there. | |
| -- The Immich comparison value is just the request latency you've already measured. | |
| -- | |
| -- Share the full output — especially the three EXPLAIN ANALYZE plans. | |
| -- 1. Dataset shape | |
| SELECT 'total_assets' AS label, COUNT(*)::text AS value FROM asset; | |
| SELECT 'own_assets_top5' AS label, "ownerId"::text || ' -> ' || COUNT(*)::text AS value | |
| FROM asset GROUP BY "ownerId" ORDER BY 2 DESC LIMIT 5; | |
| SELECT 'space_count' AS label, COUNT(*)::text AS value FROM shared_space; | |
| SELECT 'space_asset_rows' AS label, COUNT(*)::text AS value FROM shared_space_asset; | |
| SELECT 'space_library_rows' AS label, COUNT(*)::text AS value FROM shared_space_library; | |
| SELECT 'smart_search_rows' AS label, COUNT(*)::text AS value FROM smart_search; | |
| -- 2. vchord config + indexes | |
| SHOW vchordrq.probes; | |
| SELECT schemaname, tablename, indexname, indexdef FROM pg_indexes | |
| WHERE tablename IN ('smart_search', 'shared_space_asset', 'shared_space_library', 'asset') | |
| ORDER BY tablename, indexname; | |
| -- 3. Planner stats (fresh) | |
| ANALYZE asset; | |
| ANALYZE shared_space_asset; | |
| ANALYZE shared_space_library; | |
| ANALYZE smart_search; | |
| -- 4. Baseline EXPLAIN: ownerId-only (upstream-equivalent plan) | |
| EXPLAIN (ANALYZE, BUFFERS) | |
| SELECT asset.id FROM asset | |
| INNER JOIN smart_search ON asset.id = smart_search."assetId" | |
| WHERE asset."ownerId" = (SELECT id FROM "user" ORDER BY "createdAt" LIMIT 1) | |
| ORDER BY smart_search.embedding <=> (SELECT embedding FROM smart_search LIMIT 1) | |
| LIMIT 100; | |
| -- 5. Fork EXPLAIN: OR-EXISTS (Gallery-equivalent plan) | |
| EXPLAIN (ANALYZE, BUFFERS) | |
| SELECT asset.id FROM asset | |
| INNER JOIN smart_search ON asset.id = smart_search."assetId" | |
| WHERE ( | |
| asset."ownerId" = (SELECT id FROM "user" ORDER BY "createdAt" LIMIT 1) | |
| OR EXISTS ( | |
| SELECT 1 FROM shared_space_asset ssa | |
| WHERE ssa."assetId" = asset.id | |
| AND ssa."spaceId" IN (SELECT id FROM shared_space LIMIT 100) | |
| ) | |
| OR EXISTS ( | |
| SELECT 1 FROM shared_space_library ssl | |
| WHERE ssl."libraryId" = asset."libraryId" | |
| AND ssl."spaceId" IN (SELECT id FROM shared_space LIMIT 100) | |
| ) | |
| ) | |
| ORDER BY smart_search.embedding <=> (SELECT embedding FROM smart_search LIMIT 1) | |
| LIMIT 100; | |
| -- 6. Candidate fix: IN-via-UNION-CTE | |
| EXPLAIN (ANALYZE, BUFFERS) | |
| WITH accessible AS ( | |
| SELECT id FROM asset WHERE "ownerId" = (SELECT id FROM "user" ORDER BY "createdAt" LIMIT 1) | |
| UNION | |
| SELECT "assetId" FROM shared_space_asset WHERE "spaceId" IN (SELECT id FROM shared_space LIMIT 100) | |
| UNION | |
| SELECT a.id FROM asset a | |
| JOIN shared_space_library ssl ON a."libraryId" = ssl."libraryId" | |
| WHERE ssl."spaceId" IN (SELECT id FROM shared_space LIMIT 100) | |
| ) | |
| SELECT asset.id FROM asset | |
| INNER JOIN smart_search ON asset.id = smart_search."assetId" | |
| WHERE asset.id IN (SELECT id FROM accessible) | |
| ORDER BY smart_search.embedding <=> (SELECT embedding FROM smart_search LIMIT 1) | |
| LIMIT 100; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment