gendesign/data/sql/66_indexes_recommend.sql
lekss361 e22f86bc06 audit-fix: 27mo окно, MODE bucket, индексы recommend_mix
B1: дефолт months_window 12→24, расширение fallback 24→27 (max архив).
2024Q1+Q2 теперь реально влияют на recommend_mix (raw 784→3815 сделок
для Академического, ×4.9).

B2: per-bucket elasticity через MODE по семантике (is_studio+rooms),
а не PERCENTILE_CONT(0.5) по total_area. ЖК с mix studios+3к больше не
попадают в bucket "1-к" как среднее. Для Академического: 1-к получает
208 точек регрессии (vs 118), slope -1.17.

B3: share_window_months и elasticity_window_months в API scope —
прозрачность для UI tooltip про рассинхрон окон (24mo rosreestr vs
36mo sale_graph).

B4: cad_buildings.floors при INSERT больше НЕ приводится к INT —
NSPD отдаёт диапазоны "1-2", "2-3" которые теряются как NULL. Хранится
как TEXT, аналитика делает CAST через regex.

R1: data/sql/66_indexes_recommend.sql — 4 индекса для горячего пути
recommend_mix (sale_graph composite, kn_objects partial, kn_flats partial,
cad_buildings partial). Применены в проде через MCP.

R3: ON CONFLICT в insert_buildings теперь обновляет ВСЕ изменяемые
поля (purpose, address, floors, geom, registration_date) — раньше при
re-scrape апдейтились только cost/area/year, остальное игнорилось.
2026-04-30 22:41:43 +03:00

49 lines
3.1 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- Индексы под горячий путь recommend_mix (analytics_queries.py:recommend_mix).
--
-- Без них типичный POST /analytics/recommend/mix делает 3-5 seq-scan'ов на
-- 5М-строчных таблицах и тратит 1-2 сек. Цель — <500мс.
--
-- Идемпотентно через CREATE INDEX IF NOT EXISTS.
-- CONCURRENTLY НЕ используется (psql сессия с несколькими операциями) —
-- если будет блок-issue в проде, применять каждый CREATE отдельно.
-- 1) sale_graph: JOIN obj_id × type='apartments' × report_month
-- Используется в _elasticity_coef и _elasticity_per_bucket_coef.
-- Текущие индексы: (obj_id, snapshot_date), (report_month, type) — но не
-- покрывают composite seek по obj_id + type + report_month range.
CREATE INDEX IF NOT EXISTS sg_obj_type_month_idx
ON domrf_kn_sale_graph (obj_id, type, report_month DESC);
-- 2) Active competitors lookup: (district_name, obj_class, site_status)
-- Используется в _active_competitors_count, который вызывается до 3 раз
-- (каскадный fallback district+class → district → region) на каждый запрос.
-- Partial index по site_status='Строящиеся' — это то, что мы реально ищем.
CREATE INDEX IF NOT EXISTS obj_district_class_active_idx
ON domrf_kn_objects (district_name, obj_class, region_cd)
WHERE site_status = 'Строящиеся';
-- 3) Per-bucket flats lookup: (obj_id, total_area)
-- Используется в _elasticity_per_bucket_coef для группировки sale_graph
-- по «доминирующему bucket» каждого ЖК. Partial index по area-диапазону
-- который мы реально считаем (15..200 м²).
CREATE INDEX IF NOT EXISTS flats_obj_area_idx
ON domrf_kn_flats (obj_id, total_area)
WHERE total_area BETWEEN 15 AND 200;
-- 4) Cadastre baseline: (cost_value, area) — partial для строений
-- с заполненными ценой и площадью. Используется в _district_cadastre_baseline
-- + view v_zk_rosreestr_velocity. Также без этого индекса при PERCENTILE_CONT
-- по cost_value/area делается seq-scan на 10K строк × spatial-join.
CREATE INDEX IF NOT EXISTS buildings_cost_area_idx
ON cad_buildings (cost_value, area)
WHERE cost_value IS NOT NULL AND area IS NOT NULL;
-- Комментарии для будущей навигации.
COMMENT ON INDEX sg_obj_type_month_idx IS
'Hot path: JOIN domrf_kn_sale_graph по obj_id+type для regression в _elasticity_*.';
COMMENT ON INDEX obj_district_class_active_idx IS
'Hot path: _active_competitors_count + recommend_mix scope queries (Partial: site_status=Строящиеся).';
COMMENT ON INDEX flats_obj_area_idx IS
'Hot path: per-bucket median total_area для _elasticity_per_bucket_coef.';
COMMENT ON INDEX buildings_cost_area_idx IS
'Hot path: cadastre median ₽/м² в _district_cadastre_baseline.';