gendesign/_wt-cadval/data/sql/175_v_objective_lots_latest.sql
bot-backend 542ff1c9ca docs(tradein/domclick): два комментария описывали пул, которого нет с миграции 253
Оба места утверждали, что у Домклика один выделенный резидентный прокси и
пула нет. Это перестало быть правдой ещё в #2800 (миграция 253 сняла
резервацию узла), но текст остался — и именно на него опирался тикет #3189,
поставленный под «калибровку» ограничения, которого не существует.
Свип к тому же ходит через пул давно (serp.py:359), а бэкфилл подключён к
нему в PR #3222.

Заодно докстринг называл не тот ограничитель: свип кладёт не счётчик
провалов lease, а break по первому DomClickBlockedError (#2854) — до
ротации дело не доходит ни при каком счётчике, отсюда buckets_completed=0.

Только комментарии, поведение не меняется. Миграция 175 уже применена, а
_schema_migrations трекает по имени файла без checksum — правка текста
её не перезапустит.
2026-08-29 18:57:25 +03:00

67 lines
5.1 KiB
PL/PgSQL
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.

-- Контекст: #1964 (эпик #1953) — physflat-дедуп current-state потребителей
-- objective_lots через общий VIEW.
--
-- objective_lots — current-state UPSERT (UNIQUE objective_lot_id, ON CONFLICT DO
-- UPDATE), НЕ snapshot-append: всего 5 distinct snapshot_date. Инфляция строк
-- (~2.91×: прод 2026-06-28 — 1 753 283 сырых квартир-строки vs 603 049 физлотов)
-- возникает потому, что Объектив за время пере-листингов присваивает ОДНОМУ
-- физическому лоту (project_name, corpus_name, section, floor, lot_number)
-- НЕСКОЛЬКО objective_lot_id. История лотов живёт в ОТДЕЛЬНОЙ objective_lots_history
-- (её НЕ трогаем — это корректный time-series).
--
-- View отдаёт ТОТ ЖЕ набор колонок, что и objective_lots (ol.* — прод-проверка:
-- 51 base cols == 51 view cols), по ОДНОЙ строке на физлот — последний снапшот
-- (snapshot_date DESC, tie-break id DESC). objective_lot_id в результате уникален
-- (603 049 строк = 603 049 distinct objective_lot_id, 0 NULL) → потребители,
-- которым нужна fan-out-защита по маппингу (competitors._SOLD_COUNT_SQL), могут
-- использовать COUNT(DISTINCT objective_lot_id) поверх view.
--
-- ⚠ ПЛАН/ИНДЕКС (deep-review #1964, прод-EXPLAIN 2026-06-28): partial-индекс
-- objective_lots_physflat_latest_idx (миграция 173, WHERE premise_kind='квартира')
-- НЕ обслуживает этот view. Внутри view НЕТ premise-фильтра, а внешний
-- WHERE premise_kind/district потребителя НЕ проталкивается НИЖЕ DISTINCT ON →
-- индекс-173 не применим. View материализует ВСЮ таблицу: Parallel Seq Scan +
-- external Sort 1.76M строк → ~5.8 s (count по одному району).
-- ПОЛНЫЙ индекс (project,corpus,section,floor,lot_number,snapshot_date DESC,id DESC)
-- НЕ помогает и НЕ добавлен: DISTINCT ON отдаёт ol.* (51 кол., width≈945) →
-- index-only-unique невозможен; 605k heap-проб через 142 MB индекс ДОРОЖЕ
-- seq-scan+sort (планировщик его игнорирует: forced index-path всё равно ~3.9 s).
-- 142 MB write-amp ради нуля на request-path + замедление bulk-INSERT objective-
-- scrape — не берём. Подтверждает исходное решение #1964 «новый индекс НЕ добавляем».
--
-- Следствие: view применяем ТОЛЬКО к BATCH/широким консьюмерам, где полная
-- материализация амортизирована или кэширована (supply_layers L1 группирует ВСЕ
-- районы; competitors._SOLD_COUNT_SQL — по mapping; special_indices; admin; landing).
-- REQUEST-PATH консьюмеры внутри analyze_parcel с фильтром по ОДНОМУ району
-- (concepts._OBJECTIVE_MEDIAN_SQL, parcels district-price/geo-median) view НЕ
-- используют — у них inline DISTINCT ON с district, протолкнутым В CTE (bitmap по
-- району ~240k строк + sort ~19 MB → ~1.7 s vs 5.8 s через view). Дедуп платится в
-- любом случае (старый 303 ms был быстрым потому что считал РАЗДУТЫЕ сырые строки).
--
-- #1959 уже устранил инфляцию ВНУТРИ compute_market_metrics (inline DISTINCT ON в
-- _STOCK_SQL/_SALES_WINDOW_SQL) и его 9 forecast/scoring-вызовов — НЕ дублируем.
--
-- НЕ трогаем (time-series, корректны): sales_series._SOURCE_B_SQL,
-- objective_lots_history, mv_sales_tracker_*.
--
-- Порядок: миграция ПЕРВОЙ (deploy first), затем backend-код, читающий view.
-- Idempotent: CREATE OR REPLACE VIEW. Self-wrapped BEGIN/COMMIT.
-- Прод DRY-RUN (BEGIN; CREATE OR REPLACE VIEW; SELECT count; ROLLBACK):
-- view kvartira = 603 049 (vs 1 753 283 raw), колонки 51==51 ✓.
BEGIN;
CREATE OR REPLACE VIEW v_objective_lots_latest AS
SELECT DISTINCT ON (project_name, corpus_name, section, floor, lot_number) ol.*
FROM objective_lots ol
ORDER BY project_name, corpus_name, section, floor, lot_number,
snapshot_date DESC, id DESC;
COMMENT ON VIEW v_objective_lots_latest IS
'#1964: physflat-deduped current state of objective_lots — one row per '
'(project_name, corpus_name, section, floor, lot_number) at the latest '
'snapshot (snapshot_date DESC, id DESC). objective_lots stores ~2.91x '
'inflated rows (multiple objective_lot_id per physical flat across '
're-listings); this view collapses to ~603k physical flats. History lives '
'in objective_lots_history (do not use this view for time-series).';
COMMIT;