perf(objective_lots): inline DISTINCT ON for 3 view-fullscan consumers + cache landing stats (#1953) #2067
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
вторичка
ИРД
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#2067
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/perf-view-fullscan-1953"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Контекст
Perf-батч #2 (follow-up эпика #1953, тот же класс что #2054 competitors). #1964 (PR #2032) репойнтнул несколько потребителей на view
v_objective_lots_latest. ЕгоDISTINCT ON— оптимизационный барьер: внешний WHERE/JOIN НЕ проталкивается ниже → планировщик материализует ВСЮobjective_lots(1.76M, Parallel Seq Scan width≈917-962 + external merge sort 50-100МБ/воркер) ПЕРЕД фильтрацией → ~6-8с на каждый вызов. Проактивный data-health хунт нашёл 3 оставшихся таких потребителя (parcels.py уже был inline из #1964).Изменения
landing.py_query_stats/landing/stats(хоумпейдж) uncached, KPI3 = full-view-aggregate 6694мс/loadweather_cache)supply_layers.py_L1_OPEN_SQLdistrict_class_idx, ~0.45с (~13×)special_indices.py_ARTIFICIAL_DEMAND_SQLКорректность (критично — feed forecast)
Тонкость:
class— меняющийся атрибут (248 transient-физлотов из 605k меняют класс между снапшотами). Фильтр class ДО дедупа дрейфил vs view (стандарт +193, бизнес +20). Поэтому стабильные фильтры (premise_kind 0-transient, district 4-transient — index-драйвер, осознанный компромисс как parcels.py) проталкиваются до DISTINCT ON, а меняющиеся (class, is_sold, contract_date) — после.Прод-верификация бит-в-бит (исправленный inline vs view):
DISTINCT ON-ключ +ORDER BY ... snapshot_date DESC, id DESCточно совпадают с175_v_objective_lots_latest.sql. Без миграции (используются существующиеobjective_lots_physflat_covering_idx/objective_lots_district_class_idx).Verify
@lightmyself тесты прошли ✅ — красный был на первом коммите (
e3327359), это устаревший тест, а не реальная регрессия.Что произошло: тест
test_sql_reads_physflat_view(из #1964) ассертил, что_L1_OPEN_SQLчитает из viewv_objective_lots_latest. Этот PR как раз заменяет view → inlineDISTINCT ON(view = оптимизационный барьер → full-scan 1.76M ~6с). Т.е. тест проверял ровно то поведение, которое PR осознанно меняет.Фикс: обновил тест под новый инвариант во втором коммите
c16e0718— теперь он требует physflat-дедуп черезDISTINCT ON(это и был анти-регресс #1964: не читать СЫРОЙ objective_lots без дедупа, иначе units_available раздулся бы ~2.91×) и запрещает view. Локально весь backend-сьют: 1966 passed, 4 skipped.Состояние:
c16e0718(смерженный код): весь CI зелёный (backend-tests=success)c8e7cb1c: build-backend/worker/frontend + deploy = success/landing/stats7.1с→0.0000с (TTL-кэш),supply_layers._L1_OPEN_SQL5.9→0.77с,special_indices._ARTIFICIAL_DEMAND_SQL6.7→0.40с (n_sold/n_mortgage 9601/5393 — бит-в-бит = view)PR смержен и задеплоен. Если смотришь на вкладку commits — красный X на
e3327359это «до фикса»; актуальный HEADc16e0718зелёный.