Как реализовать добавление поля в таблицу для вычисленных данных
Что проверяют
Умеете ли вы выбрать, где жить вычисленному значению: считать при чтении, хранить в генерируемой колонке или материализовать в пайплайне. Следом спрашивают, как заполнить поле на большой таблице и что делать, если формула поменялась.
Как отвечать
Начните с вопроса, от чего зависит значение: только от колонок той же строки, от других таблиц или от времени. От этого зависит инструмент:
- вычисление при чтении: выражение в запросе или представление (
VIEW). Данные не дублируются, но выражение считается на каждом запросе; - генерируемая колонка: в PostgreSQL
total_price numeric(12,2) GENERATED ALWAYS AS (quantity * price_per_item) STORED. Считается при записи, вручную не меняется. С PostgreSQL 18 есть и виртуальные генерируемые колонки, они вычисляются при чтении и места не занимают. Ограничение: только колонки той же строки и неизменяемые функции; - зависимость от других таблиц: материализованное представление с
REFRESH MATERIALIZED VIEW CONCURRENTLYили триггер. Триггер держит значение свежим, но замедляет запись и прячет логику; - хранилище и пайплайн: в аналитике поле обычно считают в модели dbt или в шаге ETL, а сырой слой не трогают. В ClickHouse для этого есть колонки
MATERIALIZEDиALIAS.
Для признаков в ML добавьте про корректность во времени: признак на дату события считается только из данных, доступных к этой дате, иначе в обучение протекает будущее.
Заполнение существующих строк: в PostgreSQL ADD COLUMN без значения по умолчанию меняет только метаданные, а бэкфилл идёт пачками по несколько тысяч строк, а не одним UPDATE на всю таблицу. Деньги храните в numeric, не во float.
Где спотыкаются
Добавляют обычную колонку, один раз заполняют её UPDATE и не предусматривают обновления. Через месяц значения расходятся с исходными полями, и никто не знает, каким верить.
Запускают UPDATE на миллионы строк одной транзакцией. Долгие блокировки, раздувание таблицы и отставание реплик.
Путают синтаксис СУБД: запись ADD COLUMN x AS (expr) взята из SQL Server, в PostgreSQL она не сработает, там нужен GENERATED ALWAYS AS.