feat(tradein): позиция квартиры внутри когорты аналогов — перцентиль (#2899) #2926

Merged
bot-backend merged 2 commits from feat/2899-market-percentile into main 2026-08-19 10:08:19 +00:00
Showing only changes of commit 9f17983689 - Show all commits

View file

@ -6,15 +6,25 @@
-- позицию по сохранённому top-10 нельзя — это другая популяция, поэтому значение
-- обязано персиститься вместе с оценкой.
--
-- smallint: диапазон значений 1..99 по построению (`_market_percentile` зажимает
-- края — «0-й перцентиль» читался бы как «дешевле всех на свете», хотя означает лишь
-- край выборки). NULL = когорта меньше MARKET_PERCENTILE_MIN_N (15) либо оценки нет.
-- smallint: диапазон 1..99 по построению (`_market_percentile` зажимает края —
-- «0-й перцентиль» читался бы как «дешевле всех на свете», хотя означает лишь край
-- выборки). NULL = когорта меньше MARKET_PERCENTILE_MIN_N (15) либо оценки нет.
-- Бэкфилла нет и быть не может: позицию старых строк восстановить не из чего.
--
-- Идемпотентно: IF NOT EXISTS. Блокировки не берёт (ADD COLUMN без DEFAULT в PG 11+
-- не переписывает таблицу).
-- ПРО ЛОКИ (#2752). ADD COLUMN без DEFAULT в PG 11+ не переписывает таблицу и держит
-- ACCESS EXCLUSIVE миллисекунды — но ЖДАТЬ его выдачи может сколько угодно, и всё это
-- время ждущий DDL стоит в очереди ПЕРЕД новыми запросами приложения к той же таблице.
-- Ровно так миграция 250 встала на 29 минут за чужой psql-сессией. lock_timeout
-- ограничивает только ожидание: не дождались — красный деплой вместо тихой очереди.
BEGIN;
SET LOCAL lock_timeout = '5s';
ALTER TABLE trade_in_estimates
ADD COLUMN IF NOT EXISTS market_percentile smallint;
COMMENT ON COLUMN trade_in_estimates.market_percentile IS
'#2899: доля аналогов дешевле этой квартиры, 1..99. NULL — когорта < 15 лотов. '
'НЕ location_index_pct (тот про район против медианы города).';
COMMIT;