-- 097_index_hygiene.sql -- #730 index hygiene: drop exact-duplicate + redundant indexes; -- de-partial is_active indexes. 87-unused sweep deferred (needs live pg_stat snapshot). -- -- Context (Issue #730): -- Duplicate drops: 5 named indexes that are exact duplicates of a surviving twin -- or covered by a UNIQUE constraint (all confirmed from migration history below). -- De-partial: 5 indexes on listings using WHERE is_active = true; since is_active -- is 100% true in production the partial predicate saves nothing — a full index -- strictly covers the same rows with no plan regression. -- -- Idempotency: -- All DROP INDEX use IF EXISTS; all CREATE INDEX use IF NOT EXISTS. -- Safe to re-run. -- -- Source evidence (each pair confirmed from migration files): -- houses_kadastr_idx2 (050:93) dup of houses_cadastral_number_idx (029:180) -- houses_addr_fp_idx (028:20) dup of houses_fingerprint_idx2 (050:90) -- listings_scraped_idx (002:59) dup of listings_scraped_desc_idx (050:62) -- listing_sources_price_divergence_idx (042:8) dup of _idx2 (050:84) -- houses_source_ext_idx (009:59) redundant — covered by UNIQUE(source,ext_house_id) (009:54) -- -- Dependencies: -- 002_core_tables.sql, 009_houses.sql, 028_matching_tables.sql, -- 029_extend_matching_valuation_dynamics.sql, 042_listing_sources_price_divergence_idx.sql, -- 050_search_optimization.sql BEGIN; -- ============================================================================= -- Step 1: Drop exact-duplicate and redundant indexes -- ============================================================================= -- dup of houses_cadastral_number_idx (029_extend_matching_valuation_dynamics.sql:180) -- same: ON houses (cadastral_number) WHERE cadastral_number IS NOT NULL DROP INDEX IF EXISTS houses_kadastr_idx2; -- dup of houses_fingerprint_idx2 (050_search_optimization.sql:90) -- same: ON houses (address_fingerprint) WHERE address_fingerprint IS NOT NULL DROP INDEX IF EXISTS houses_addr_fp_idx; -- dup of listings_scraped_desc_idx (050_search_optimization.sql:62) -- same: ON listings (scraped_at DESC) WHERE is_active = true -- Note: listings_scraped_desc_idx is also de-partialed in Step 2 below. DROP INDEX IF EXISTS listings_scraped_idx; -- dup of listing_sources_price_divergence_idx2 (050_search_optimization.sql:84) -- same: ON listing_sources (listing_id, price_rub) WHERE price_rub IS NOT NULL DROP INDEX IF EXISTS listing_sources_price_divergence_idx; -- redundant: covered by UNIQUE (source, ext_house_id) constraint (009_houses.sql:54) -- which automatically creates a unique index on the same column set. -- The plain btree here (009_houses.sql:59) is a strict duplicate of that unique index. DROP INDEX IF EXISTS houses_source_ext_idx; -- ============================================================================= -- Step 2: De-partial is_active=true indexes -- Since is_active is 100% true, the WHERE predicate saves nothing. -- A full index strictly covers the partial — no plan regression. -- ============================================================================= -- listings_geom_active_idx (050_search_optimization.sql:47) -- Original: ON listings USING GIST (geom) WHERE is_active = true DROP INDEX IF EXISTS listings_geom_active_idx; CREATE INDEX IF NOT EXISTS listings_geom_active_idx ON listings USING GIST (geom); -- listings_active_filter_idx (050_search_optimization.sql:52) -- Original: ON listings (rooms, price_rub, area_m2, scraped_at DESC) WHERE is_active = true DROP INDEX IF EXISTS listings_active_filter_idx; CREATE INDEX IF NOT EXISTS listings_active_filter_idx ON listings (rooms, price_rub, area_m2, scraped_at DESC); -- listings_house_price_idx (050_search_optimization.sql:57) -- Original: ON listings (house_id_fk, price_rub) WHERE is_active = true DROP INDEX IF EXISTS listings_house_price_idx; CREATE INDEX IF NOT EXISTS listings_house_price_idx ON listings (house_id_fk, price_rub); -- listings_scraped_desc_idx (050_search_optimization.sql:62) -- Original: ON listings (scraped_at DESC) WHERE is_active = true -- Note: listings_scraped_idx (exact duplicate) already dropped in Step 1 above. DROP INDEX IF EXISTS listings_scraped_desc_idx; CREATE INDEX IF NOT EXISTS listings_scraped_desc_idx ON listings (scraped_at DESC); -- listings_rooms_area_idx (002_core_tables.sql:58) -- Original: ON listings (rooms, area_m2) WHERE is_active = true DROP INDEX IF EXISTS listings_rooms_area_idx; CREATE INDEX IF NOT EXISTS listings_rooms_area_idx ON listings (rooms, area_m2); COMMIT;