From 8ea193c0950045ac536c923a1b99ae05b31140df Mon Sep 17 00:00:00 2001 From: "[._.]/ Adam Eivy" Date: Wed, 21 Oct 2026 13:14:49 -0700 Subject: [PATCH] Analyze person before checking the search index plan The GIN index plan test only analyzed person_search after inserting 12,000 fixture people. If autovacuum had analyzed person earlier while it was small, the planner still believed person held a handful of rows, drove the join from a sequential scan of person and never used the GIN index. That made the integration suite fail intermittently on main. Analyzing both tables makes the plan depend on the fixture data, not on autovacuum timing. --- tests/integration/db/postgresSearch.spec.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/integration/db/postgresSearch.spec.ts b/tests/integration/db/postgresSearch.spec.ts index 6e09168..89556f0 100644 --- a/tests/integration/db/postgresSearch.spec.ts +++ b/tests/integration/db/postgresSearch.spec.ts @@ -221,7 +221,10 @@ describePostgres('PostgreSQL person search and production routes', () => { it('uses the GIN document index for selective prefixes on representative data', async () => { await store.run(`INSERT INTO person(person_id, display_name) SELECT 'fixture-' || n, 'Common Person ' || n FROM generate_series(1, 12000) AS n`); - await store.run('ANALYZE person_search'); + // Analyze both sides of the join: stale person stats (e.g. from an earlier + // autovacuum while the table was tiny) make the planner drive from a seq + // scan of person and skip the GIN index. + await store.run('ANALYZE person, person_search'); const plans = await store.queryAll(`EXPLAIN (FORMAT JSON) SELECT p.person_id FROM person p WHERE ${PERSON_SEARCH_MATCH}`, { query: personSearchQuery('Cartograph') }); expect(JSON.stringify(plans)).toContain('idx_person_search_document');