Найдено research-тикетом #129 (заметка docs/research/2026-08-22-distributed-join.md, ветка research/distributed-join) — только чтением, стенд не менялся.
Находка и причина
Заказы в ODS не разложены по своему ключу шардирования: 1189 из 1662
заказов лежат на обоих шардах одинаковыми строками, count() по ods.order_dist даёт 2851 вместо 1662. События целы: все строки ods.event разложены по cityHash64(ClientID).
Причина — заводское parallel_distributed_insert_select = 2: обе
вставки sql/ods/order_parse.sql (INSERT INTO ods.order_dist … FROM stg.orders_raw_dist) выполняются локально на каждом шарде, минуя ключ
шардирования цели (cityHash64(order_id)). Слепок переотправляет заказ
каждый день окна изменяемости, сырьё день ото дня ложится по-разному —
и копии одного заказа расползаются по шардам, где ReplacingMergeTree
через границу шарда их не схлопывает.
Цель
Заказы в ODS лежат каждый на своём шарде по cityHash64(order_id), и
шаг разбора не воспроизводит дефект на следующих слепках.
Порядок
Сначала механизм. Сверить семантику значений parallel_distributed_insert_select через MCP Context7 и выбрать то,
при котором инициатор раскладывает строки по ключу шардирования цели
(ожидаемо 0). Добавить настройку в SETTINGS обеих вставок sql/ods/order_parse.sql с комментарием-доводом.
Потом данные. Адресная очистка: TRUNCATE локальных ods.order и ods.order_errors ON CLUSTER (make clean не нужен:
состояние — только эти две таблицы; сырьё в STG не трогать — оно
точка повтора). Затем повторный разбор всех порций тем же шагом: по
списку SELECT DISTINCT _load_id FROM stg.orders_raw_dist.
Перед очисткой убедиться, что сырьё полно (срок жизни сырья ещё не
съел ранние порции — storage.md, «Срок жизни сырья»); если нет —
вместо п. 2 make rebuild-storage с переигрыванием мира.
Прожить следующий модельный день и повторить проверку раскладки.
Критерии приёмки
Семантика parallel_distributed_insert_select сверена (Context7);
значение и довод — комментарием у обеих вставок sql/ods/order_parse.sql.
docs/architecture/storage.md, «Раскладка по шардам», тем же PR:
описан капкан «INSERT из Distributed в Distributed при
несовпадающих ключах» — он ждёт и будущие сборки DDS
(развилки #130 и #134 карты #127).
Заказы и брак переложены: проверочный запрос ниже даёт 0; uniqExact(order_id) по ods.order_dist не изменился после
перекладки.
После приёма следующего слепка проверка раскладки снова даёт 0.
Границы
DDL не менять: ключи шардирования *_dist верны, дефект в исполнении
вставки.
Стендовые цели карты проверок остаются зелёными: make smoke, make check-clickhouse.
Найдено research-тикетом #129 (заметка
`docs/research/2026-08-22-distributed-join.md`, ветка
`research/distributed-join`) — только чтением, стенд не менялся.
## Находка и причина
Заказы в ODS не разложены по своему ключу шардирования: 1189 из 1662
заказов лежат на обоих шардах одинаковыми строками, `count()` по
`ods.order_dist` даёт 2851 вместо 1662. События целы: все строки
`ods.event` разложены по `cityHash64(ClientID)`.
Причина — заводское `parallel_distributed_insert_select = 2`: обе
вставки `sql/ods/order_parse.sql` (`INSERT INTO ods.order_dist … FROM
stg.orders_raw_dist`) выполняются локально на каждом шарде, минуя ключ
шардирования цели (`cityHash64(order_id)`). Слепок переотправляет заказ
каждый день окна изменяемости, сырьё день ото дня ложится по-разному —
и копии одного заказа расползаются по шардам, где `ReplacingMergeTree`
через границу шарда их не схлопывает.
## Цель
Заказы в ODS лежат каждый на своём шарде по `cityHash64(order_id)`, и
шаг разбора не воспроизводит дефект на следующих слепках.
## Порядок
1. **Сначала механизм.** Сверить семантику значений
`parallel_distributed_insert_select` через MCP Context7 и выбрать то,
при котором инициатор раскладывает строки по ключу шардирования цели
(ожидаемо `0`). Добавить настройку в `SETTINGS` обеих вставок
`sql/ods/order_parse.sql` с комментарием-доводом.
2. **Потом данные.** Адресная очистка: `TRUNCATE` локальных
`ods.order` и `ods.order_errors` ON CLUSTER (`make clean` не нужен:
состояние — только эти две таблицы; сырьё в STG не трогать — оно
точка повтора). Затем повторный разбор всех порций тем же шагом: по
списку `SELECT DISTINCT _load_id FROM stg.orders_raw_dist`.
Перед очисткой убедиться, что сырьё полно (срок жизни сырья ещё не
съел ранние порции — `storage.md`, «Срок жизни сырья»); если нет —
вместо п. 2 `make rebuild-storage` с переигрыванием мира.
3. Прожить следующий модельный день и повторить проверку раскладки.
## Критерии приёмки
- [x] Семантика `parallel_distributed_insert_select` сверена (Context7);
значение и довод — комментарием у обеих вставок
`sql/ods/order_parse.sql`.
- [x] `docs/architecture/storage.md`, «Раскладка по шардам», тем же PR:
описан капкан «INSERT из Distributed в Distributed при
несовпадающих ключах» — он ждёт и будущие сборки DDS
(развилки #130 и #134 карты #127).
- [x] Заказы и брак переложены: проверочный запрос ниже даёт 0;
`uniqExact(order_id)` по `ods.order_dist` не изменился после
перекладки.
- [x] После приёма следующего слепка проверка раскладки снова даёт 0.
## Границы
- DDL не менять: ключи шардирования `*_dist` верны, дефект в исполнении
вставки.
- События (`ods.event`) не трогать — целы.
- Общий способ загрузки DDS здесь не решать — это развилки #130 и #134
карты #127; сюда только заказы и предупреждение в доке.
- Сырьё STG не чистить и не перекладывать: его раскладка — свойство
доставки, читатель среза фильтрует по `_load_id`.
## Сначала прочитать
- `docs/research/2026-08-22-distributed-join.md` — запросы и цифры;
- `docs/architecture/storage.md` — «Раскладка по шардам», «Срок жизни
сырья»;
- `sql/ods/order_parse.sql`, `dags/orders_ingest.py` — шаг разбора и
кто его запускает;
- ADR 0008 (приём заказов), ADR 0010 (версии заказов в ODS).
## Команды проверки
Клиент ClickHouse — по ADR 0007. Межшардовые дубли (ожидается 0):
```sql
SELECT countIf(shards > 1) AS mislaid
FROM (
SELECT order_id, uniqExact(hostName()) AS shards
FROM cluster('clickstream_cluster', ods.order)
GROUP BY order_id
);
```
Сохранность вершины версий до/после перекладки:
```sql
SELECT uniqExact(order_id) FROM ods.order_dist;
SELECT count() FROM ods.order_v;
```
Стендовые цели карты проверок остаются зелёными: `make smoke`,
`make check-clickhouse`.
Влито в main PR #138 (544e500). Все критерии приёмки закрыты: настройка сверена и закомментирована у обеих вставок, капкан описан в storage.md, заказы переложены (межшардовые дубли 0, uniqExact не изменился), после следующего слепка проверка снова даёт 0. Замеры — в «Что проверено» storage.md и orders/ingestion.md.
Влито в main PR #138 (544e500). Все критерии приёмки закрыты: настройка сверена и закомментирована у обеих вставок, капкан описан в storage.md, заказы переложены (межшардовые дубли 0, uniqExact не изменился), после следующего слепка проверка снова даёт 0. Замеры — в «Что проверено» storage.md и orders/ingestion.md.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Найдено research-тикетом #129 (заметка
docs/research/2026-08-22-distributed-join.md, веткаresearch/distributed-join) — только чтением, стенд не менялся.Находка и причина
Заказы в ODS не разложены по своему ключу шардирования: 1189 из 1662
заказов лежат на обоих шардах одинаковыми строками,
count()поods.order_distдаёт 2851 вместо 1662. События целы: все строкиods.eventразложены поcityHash64(ClientID).Причина — заводское
parallel_distributed_insert_select = 2: обевставки
sql/ods/order_parse.sql(INSERT INTO ods.order_dist … FROM stg.orders_raw_dist) выполняются локально на каждом шарде, минуя ключшардирования цели (
cityHash64(order_id)). Слепок переотправляет заказкаждый день окна изменяемости, сырьё день ото дня ложится по-разному —
и копии одного заказа расползаются по шардам, где
ReplacingMergeTreeчерез границу шарда их не схлопывает.
Цель
Заказы в ODS лежат каждый на своём шарде по
cityHash64(order_id), ишаг разбора не воспроизводит дефект на следующих слепках.
Порядок
parallel_distributed_insert_selectчерез MCP Context7 и выбрать то,при котором инициатор раскладывает строки по ключу шардирования цели
(ожидаемо
0). Добавить настройку вSETTINGSобеих вставокsql/ods/order_parse.sqlс комментарием-доводом.TRUNCATEлокальныхods.orderиods.order_errorsON CLUSTER (make cleanне нужен:состояние — только эти две таблицы; сырьё в STG не трогать — оно
точка повтора). Затем повторный разбор всех порций тем же шагом: по
списку
SELECT DISTINCT _load_id FROM stg.orders_raw_dist.Перед очисткой убедиться, что сырьё полно (срок жизни сырья ещё не
съел ранние порции —
storage.md, «Срок жизни сырья»); если нет —вместо п. 2
make rebuild-storageс переигрыванием мира.Критерии приёмки
parallel_distributed_insert_selectсверена (Context7);значение и довод — комментарием у обеих вставок
sql/ods/order_parse.sql.docs/architecture/storage.md, «Раскладка по шардам», тем же PR:описан капкан «INSERT из Distributed в Distributed при
несовпадающих ключах» — он ждёт и будущие сборки DDS
(развилки #130 и #134 карты #127).
uniqExact(order_id)поods.order_distне изменился послеперекладки.
Границы
*_distверны, дефект в исполнениивставки.
ods.event) не трогать — целы.карты #127; сюда только заказы и предупреждение в доке.
доставки, читатель среза фильтрует по
_load_id.Сначала прочитать
docs/research/2026-08-22-distributed-join.md— запросы и цифры;docs/architecture/storage.md— «Раскладка по шардам», «Срок жизнисырья»;
sql/ods/order_parse.sql,dags/orders_ingest.py— шаг разбора икто его запускает;
Команды проверки
Клиент ClickHouse — по ADR 0007. Межшардовые дубли (ожидается 0):
Сохранность вершины версий до/после перекладки:
Стендовые цели карты проверок остаются зелёными:
make smoke,make check-clickhouse.Влито в main PR #138 (
544e500). Все критерии приёмки закрыты: настройка сверена и закомментирована у обеих вставок, капкан описан в storage.md, заказы переложены (межшардовые дубли 0, uniqExact не изменился), после следующего слепка проверка снова даёт 0. Замеры — в «Что проверено» storage.md и orders/ingestion.md.