chore(tradein/db): снести DEPRECATED-колонку listings.ceiling_height #2799

Merged
bot-backend merged 1 commit from chore/2699-drop-ceiling-height into main 2026-08-09 17:51:16 +00:00
Collaborator

Summary

Хвост #2699. Миграция 238 свела высоту потолков к канону ceiling_height_m и намеренно оставила старую колонку: «сначала прод должен подтвердить, что колонку никто не пишет и не читает. Снос — отдельным шагом». Подтверждение получено — ниже числа.

251_listings_drop_ceiling_height.sql: ALTER TABLE listings DROP COLUMN IF EXISTS ceiling_height под SET LOCAL lock_timeout = '5s'.

Критерий «писателей нет» — записан ДО, выполнен

count(ceiling_height) обязан остаться 8552 (8554 из #2699 минус 2 мусорных значения cian, обнулённых шагом 1 миграции 238):

замер ceiling_height ceiling_height_m
07.08, сразу после 238 8552 15 591
09.08 16:54 UTC 8552 16 133
09.08 16:57 UTC 8552 16 147
09.08 17:16 UTC 8552 16 153

Контроль, что замер не мёртвый. «Ничего не изменилось» одинаково выглядит и при остановленном скрейпинге, поэтому нужен признак живости: за 2.5 минуты между замерами канон вырос 16 133 → 16 147, а last_seen_at строк с непустым ceiling_height обновлялся в ту же минуту, что и замер. То есть UPDATE идут по этим самым строкам прямо сейчас и сносимую колонку не трогают — это сильнее, чем «двое суток тишины».

Потребители — сверка на origin/main

git grep -n 'ceiling_height\b' origin/main -- '*.py' '*.ts' '*.tsx' '*.sql' минус ceiling_height_m: обращений к колонке не осталось. Что в выдаче и почему это не потребители:

  • имена полей Python-датаклассов enrichment'ов (CianEnrichment.ceiling_height, YandexEnrichment.ceiling_height) — атрибуты объектов, не колонки;
  • CAST(:ceiling_height AS numeric) в yandex/detail.py:600имя бинд-параметра, присваивается он колонке ceiling_height_m (соседняя строка). То же в cian/detail.py (:ch) и base.py;
  • комментарии/докстринги с историей #2699 и тесты, которые как раз утверждают отсутствие колонки в SQL писателей (test_ceiling_height_unify_2699.py, test_scraper_admin_apis.py);
  • 019/238 — сами миграции.

Фронтовых (.ts/.tsx) вхождений нет вообще.

Зависимости в схеме — проверено на проде, все нули

проверка результат
pg_depend по атрибуту listings.ceiling_height 0
вьюхи / матвьюхи с ceiling в определении 0
индексы listings с ceiling в indexdef 0
CHECK / constraint с ceiling 0
функции и процедуры с ceiling_height в теле 0
тела обоих триггеров listings (price_change, set_geom) не упоминают
pg_publication_rel по listings (column list ломает DROP) 0 (публикаций в БД нет)
foreign tables НА listings в gendesign-БД 0

CASCADE не нужен и не добавлен: в этом продукте DROP ... CASCADE уже терял гранты FDW-пользователю (инцидент C3).

Потери данных нет

  • строк «ceiling_height есть, канона нет» — 0;
  • заполнены обе — 8552, из них расходятся значения — 0.

Всё содержимое сносимой колонки присутствует в каноне до последнего знака.

Про lock_timeout

Удержание ACCESS EXCLUSIVE дёшево и не зависит от размера: DROP COLUMN не переписывает heap, а помечает attisdropped в каталоге (в listings уже 4 таких «пенька» при 92 живых колонках). Дорого ожидание, и здесь оно дороже, чем у 250: listings — 19 GB, 97 540 строк, постоянный скрейпинг. Срабатывание таймаута = честный красный деплой через 5 с, миграция не помечается применённой, повторить в окно потише.

Порядок деплоя: код УЖЕ впереди схемы (писатели сняты PR #2779 07.08 и с тех пор на проде) — для DROP это правильный порядок, обратный уронил бы скрейпинг.

Test plan

  • scripts/check-migration-lock-timeout.py --selftest — OK; гейт на дереве: ✓ ... (проверено новых миграций: 2)
  • Негативный контроль: тот же файл с вырезанной строкой SET LOCAL::error ... блокирующий DDL без lock_timeout (ALTER TABLE listings DROP COLUMN IF EXISTS ceiling_height), exit 1
  • pytest tests/test_migrations_manifest.py — 4 passed
  • Прогон на одноразовом PostgreSQL 16.4 (postgis/postgis:16-3.4, --network none): применяется, идемпотентна при повторном прогоне (NOTICE ... skipping, exit 0), колонка снята, ceiling_height_m с данными и COMMENT на месте
  • Перед мержем: блокировок по listings — 0, транзакций длиннее 30 с в БД нет
  • После деплоя: запись в _schema_migrations, колонки нет в information_schema, count(ceiling_height_m) >= 16 153 и продолжает расти

Refs #2699

## Summary Хвост #2699. Миграция 238 свела высоту потолков к канону `ceiling_height_m` и **намеренно** оставила старую колонку: «сначала прод должен подтвердить, что колонку никто не пишет и не читает. Снос — отдельным шагом». Подтверждение получено — ниже числа. `251_listings_drop_ceiling_height.sql`: `ALTER TABLE listings DROP COLUMN IF EXISTS ceiling_height` под `SET LOCAL lock_timeout = '5s'`. ## Критерий «писателей нет» — записан ДО, выполнен `count(ceiling_height)` обязан остаться **8552** (8554 из #2699 минус 2 мусорных значения cian, обнулённых шагом 1 миграции 238): | замер | ceiling_height | ceiling_height_m | |---|---|---| | 07.08, сразу после 238 | 8552 | 15 591 | | 09.08 16:54 UTC | **8552** | 16 133 | | 09.08 16:57 UTC | **8552** | 16 147 | | 09.08 17:16 UTC | **8552** | 16 153 | **Контроль, что замер не мёртвый.** «Ничего не изменилось» одинаково выглядит и при остановленном скрейпинге, поэтому нужен признак живости: за 2.5 минуты между замерами канон вырос 16 133 → 16 147, а `last_seen_at` строк с непустым `ceiling_height` обновлялся в ту же минуту, что и замер. То есть UPDATE идут **по этим самым строкам прямо сейчас** и сносимую колонку не трогают — это сильнее, чем «двое суток тишины». ## Потребители — сверка на `origin/main` `git grep -n 'ceiling_height\b' origin/main -- '*.py' '*.ts' '*.tsx' '*.sql'` минус `ceiling_height_m`: обращений к **колонке** не осталось. Что в выдаче и почему это не потребители: - имена полей Python-датаклассов enrichment'ов (`CianEnrichment.ceiling_height`, `YandexEnrichment.ceiling_height`) — атрибуты объектов, не колонки; - `CAST(:ceiling_height AS numeric)` в `yandex/detail.py:600` — **имя бинд-параметра**, присваивается он колонке `ceiling_height_m` (соседняя строка). То же в `cian/detail.py` (`:ch`) и `base.py`; - комментарии/докстринги с историей #2699 и тесты, которые как раз **утверждают отсутствие** колонки в SQL писателей (`test_ceiling_height_unify_2699.py`, `test_scraper_admin_apis.py`); - 019/238 — сами миграции. Фронтовых (`.ts`/`.tsx`) вхождений нет вообще. ## Зависимости в схеме — проверено на проде, все нули | проверка | результат | |---|---| | `pg_depend` по атрибуту `listings.ceiling_height` | 0 | | вьюхи / матвьюхи с `ceiling` в определении | 0 | | индексы `listings` с `ceiling` в `indexdef` | 0 | | CHECK / constraint с `ceiling` | 0 | | функции и процедуры с `ceiling_height` в теле | 0 | | тела обоих триггеров `listings` (price_change, set_geom) | не упоминают | | `pg_publication_rel` по `listings` (column list ломает DROP) | 0 (публикаций в БД нет) | | foreign tables НА `listings` в gendesign-БД | 0 | `CASCADE` не нужен и **не добавлен**: в этом продукте `DROP ... CASCADE` уже терял гранты FDW-пользователю (инцидент C3). ## Потери данных нет - строк «`ceiling_height` есть, канона нет» — **0**; - заполнены обе — 8552, из них расходятся значения — **0**. Всё содержимое сносимой колонки присутствует в каноне до последнего знака. ## Про lock_timeout Удержание ACCESS EXCLUSIVE дёшево и не зависит от размера: `DROP COLUMN` не переписывает heap, а помечает `attisdropped` в каталоге (в `listings` уже 4 таких «пенька» при 92 живых колонках). Дорого **ожидание**, и здесь оно дороже, чем у 250: `listings` — 19 GB, 97 540 строк, постоянный скрейпинг. Срабатывание таймаута = честный красный деплой через 5 с, миграция не помечается применённой, повторить в окно потише. Порядок деплоя: код УЖЕ впереди схемы (писатели сняты PR #2779 07.08 и с тех пор на проде) — для DROP это правильный порядок, обратный уронил бы скрейпинг. ## Test plan - [x] `scripts/check-migration-lock-timeout.py --selftest` — OK; гейт на дереве: `✓ ... (проверено новых миграций: 2)` - [x] **Негативный контроль**: тот же файл с вырезанной строкой `SET LOCAL` → `::error ... блокирующий DDL без lock_timeout (ALTER TABLE listings DROP COLUMN IF EXISTS ceiling_height)`, exit 1 - [x] `pytest tests/test_migrations_manifest.py` — 4 passed - [x] Прогон на одноразовом PostgreSQL 16.4 (`postgis/postgis:16-3.4`, `--network none`): применяется, идемпотентна при повторном прогоне (`NOTICE ... skipping`, exit 0), колонка снята, `ceiling_height_m` с данными и COMMENT на месте - [x] Перед мержем: блокировок по `listings` — 0, транзакций длиннее 30 с в БД нет - [ ] После деплоя: запись в `_schema_migrations`, колонки нет в `information_schema`, `count(ceiling_height_m) >= 16 153` и продолжает расти Refs #2699
bot-backend added 1 commit 2026-08-09 17:17:08 +00:00
chore(tradein/db): снести DEPRECATED-колонку listings.ceiling_height
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 10s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 3m54s
a74d10ad23
Хвост #2699. Миграция 238 свела высоту потолков к канону ceiling_height_m и
намеренно оставила старую колонку: «сначала прод должен подтвердить, что
колонку никто не пишет и не читает». Подтверждение получено.

Критерий «писателей нет» был записан ДО работы: count(ceiling_height) обязан
остаться 8552. Прод: 8552 07.08 (сразу после 238), 8552 09.08 16:54 UTC,
8552 в 16:57. Двое суток без единой записи.

Контроль, что замер не мёртвый (иначе «ничего не изменилось» одинаково
выглядит и при остановленном скрейпинге): за те же 2.5 минуты между двумя
замерами count(ceiling_height_m) вырос 16133 → 16147, а last_seen_at строк с
непустым ceiling_height обновлялся в минуту замера. UPDATE по этим самым
строкам идут прямо сейчас и сносимую колонку не трогают.

Потребители сверены на origin/main (не в рабочей копии): обращений к КОЛОНКЕ
не осталось. В выдаче grep только имена полей датаклассов enrichment'ов,
имя бинд-параметра `:ceiling_height`, который присваивается ceiling_height_m
(yandex/detail.py:600), комментарии с историей и тесты, утверждающие
отсутствие колонки в SQL писателей. Фронтовых вхождений нет.

Зависимости в схеме проверены на проде, все нули: pg_depend по атрибуту,
вьюхи/матвьюхи, индексы, CHECK, функции, тела обоих триггеров listings,
publication column lists, foreign tables в gendesign-БД. CASCADE не нужен и
не добавлен — в этом продукте DROP ... CASCADE уже терял гранты FDW-юзеру.

Потери данных нет: строк «ceiling_height есть, канона нет» — 0; заполнены обе
у 8552 строк, расхождений 0.

lock_timeout обязателен и здесь дороже, чем у 250: удержание ACCESS EXCLUSIVE
дёшево (DROP COLUMN не переписывает heap, только attisdropped в каталоге — в
listings уже 4 таких пенька), но ожидание идёт по таблице в 19 GB, по которой
постоянно пишет скрейпинг.

Обе миграции прогнаны на одноразовом PostgreSQL 16.4 (postgis/postgis:16-3.4,
--network none) на минимальном слепке схемы: применяются, идемпотентны при
повторном прогоне, дубль индекса снят, колонка снята, ceiling_height_m и оба
COMMENT на месте.

Refs #2699
bot-backend merged commit 687bd38322 into main 2026-08-09 17:51:16 +00:00
bot-backend deleted branch chore/2699-drop-ceiling-height 2026-08-09 17:51:18 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#2799
No description provided.