Files
clickstream-data-platform/sql/ddl/05-dic-catalog.sql
T
ddadminandClaude Opus 5 d77acfdf6c fix(docs): расхождение нод при обновлении словаря названо верно
Зачем: горячее ревью поймало ошибку в трёх местах сразу. Было записано, что
после правки каталога ноды расходятся до тридцати секунд — число взято из
ширины окна LIFETIME(MIN 60 MAX 90). Ширина тут ни при чём: каждая нода ждёт
правки от нуля до верхней границы окна, фазы у них независимы, поэтому
расходиться они могут почти на все полторы минуты.

Что: исправлены ADR 0012, опорная точка мастер-спеки и комментарий DDL. Заодно
уточнено, что LIFETIME(0) неатомарность не предотвращал, а сжимал до разброса
исполнения SYSTEM RELOAD DICTIONARY ON CLUSTER, и что витрина выручки пока
спроектирована, а не построена.

Проверка: рассуждением, замером не подтверждалось — прежнее число тоже было
выведено, а не измерено. Замер в ADR (116 секунд на окне MIN 60 MAX 120)
относится к другому утверждению: что словарь обновляется сам.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 11:47:23 +03:00

69 lines
4.5 KiB
SQL
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.
-- Каталог товаров: подложка на файловом движке и словарь поверх неё.
--
-- Словарь читает не файл, а таблицу хранилища — намеренное усложнение
-- ([ADR 0012](../../docs/adr/0012-dictionary-home.md)). В бою справочник
-- приезжает процессом, и предложение SOURCE с запросом и учётной записью —
-- та форма, которую менти встретит; файловый источник работает, но редок.
--
-- Зона dic лежит вне цепочки STG → ODS → DDS → DM: справочник в хранилище
-- никто не производит, а читают его несколько слоёв.
-- Подложка ничего не хранит: движок File перечитывает CSV на каждом запросе,
-- поэтому правка каталога доезжает до словаря сама. Compose монтирует один и
-- тот же файл в user_files обеих нод только для чтения.
--
-- Путь считается ОТ user_files, а не от корня данных: форма
-- './user_files/catalog/products.csv' даёт FILE_DOESNT_EXIST. У файлового
-- источника словаря база пути была другой — отсюда разница с прежним DDL.
-- Типы здесь повторяют файл, а не модель: цена лежит целыми копейками, как её
-- пишет генератор. Приведение к деньгам делает словарь.
CREATE TABLE IF NOT EXISTS dic.products_file ON CLUSTER clickstream_cluster
(
sku String,
name String,
category String,
brand String,
price Int64,
demand String
)
ENGINE = File(CSVWithNames, './catalog/products.csv');
-- Пользователь dict объявлен файлом настройки и умеет одно — читать dic.
-- Назвать его обязательно: без user словарь идёт как default с пустым паролем
-- и падает с AUTHENTICATION_FAILED. Хост локальный, поэтому запрос к подложке
-- идёт без сети.
--
-- Окно обновления вместо LIFETIME(0): словарь перезагружается сам в случайный
-- момент внутри окна. Случайность разводит обращения разных серверов к
-- источнику, и цена у неё заявленная — ноды обновляются вразнобой. Ждать
-- правки каталога каждой из них приходится от нуля до верхней границы окна,
-- фазы у них независимы, поэтому расходиться они могут почти на все
-- полторы минуты: одна перезагрузилась сразу после правки, вторая ещё нет.
--
-- Ключ строковый, поэтому COMPLEX_KEY_HASHED: числовой FLAT здесь неприменим.
--
-- Цена приводится к деньгам прямо в источнике — оттого форма query, а не
-- table: словарь нормализует на входе, а не зеркалит подложку. В файле лежат
-- целые копейки, наружу словарь отдаёт Decimal(18, 2), как заказы бэкенда.
-- Единица в числе становится видна: 129000 против 1290.00.
--
-- Стык с событием на этом и стоит: в контракте события productPrice — целые
-- РУБЛИ, округление формата. Разрыв между ценой каталога и ценой в событии
-- намеренный, на нём держится урок про Float64.
CREATE DICTIONARY IF NOT EXISTS dic.products ON CLUSTER clickstream_cluster
(
sku String,
name String,
category String,
brand String,
price Decimal(18, 2),
demand String
)
PRIMARY KEY sku
SOURCE(CLICKHOUSE(
host 'localhost' port 9000 user 'dict'
query 'SELECT sku, name, category, brand, toDecimal64(price, 2) / 100 AS price, demand FROM dic.products_file'
))
LAYOUT(COMPLEX_KEY_HASHED())
LIFETIME(MIN 60 MAX 90);