perf(objective_lots): inline-pushdown competitors._SOLD_COUNT_SQL + covering physflat index (#1953) #2054

Merged
bot-backend merged 1 commit from perf/objective-lots-covering-competitors-1953 into main 2026-06-28 14:07:50 +00:00

1 commit

Author SHA1 Message Date
8074cb49ef perf(objective_lots): inline-pushdown competitors._SOLD_COUNT_SQL + covering physflat index (#1953)
All checks were successful
CI / changes (pull_request) Successful in 8s
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 2m14s
CI / backend-tests (pull_request) Successful in 14m23s
Прод EXPLAIN-охота (follow-up эпика #1953):

#1 competitors._SOLD_COUNT_SQL — фикс регрессии #1964. JOIN
v_objective_lots_latest материализовал DISTINCT ON по всей 1.76M-таблице
ДО фильтра маппинга (qual не проталкивается ниже view-DISTINCT ON) →
Parallel Seq Scan + external sort (~213 MB temp). Переписан на
inline-pushdown (зеркало #1964 / market_metrics._STOCK_SQL): фильтр
objective_complex_mapping в CTE → DISTINCT ON по СЫРОЙ objective_lots,
JOIN ON project_name (objective_lots_project_idx). Прод: 7958 → 292 ms,
вывод побайтово идентичен (15/15 obj_id, 0 mismatch). COUNT(DISTINCT
objective_lot_id) сохранён (fan-out-safety).

#2/#6/#5 миграция 176 — покрывающий physflat-индекс. EKB-wide
_STOCK_SQL/_SALES_WINDOW_SQL full-seq-scan + external sort (~140 MB temp),
т.к. partial-индекс 173 не нёс проецируемых колонок. Новый
objective_lots_physflat_covering_idx = тот же ключ + INCLUDE(rooms_int,
area_pd, sales_start_date, is_sold, contract_date, status, class) +
WHERE premise_kind='квартира'; старый _latest_idx дропнут (полностью
замещён). Прод DRY-RUN: Index Only Scan + Unique, без external sort,
5177 → 1595 ms; индекс 252 MB. ANALYZE objective_lots в конце tx.

Деплой вне недельного окна objective-scrape (кратковременный SHARE-lock
при drop+create ~252 MB индекса на 1.75M строк).
2026-06-28 18:45:47 +05:00