Ночная смена: девять утра

Три полки: raw → stg → DDS → витрина

16 мин
Чему научишься
  • видеть между источником и отчётом четыре полки, а не одну стрелку
  • для каждой полки объяснять, что означает одна строка, и проверять это запросом
  • отвечать на вопрос «сколько было заказов» так, чтобы ответ зависел от смысла полки, а не от удачного COUNT(*)
  • читать чужие названия слоёв: raw/stg/DDS/витрина, bronze/silver/gold, ODS/CDM — за разными словами часто стоит один и тот же склад

Тикет №01, часть вторая. «А данные-то целы?»

09:20. Ты ответил в Академию: за 14-е витрина не досчитана, за 13-е посчитана дважды. Через минуту приходит новый вопрос:

«Понял. А сами данные целы? Заказы за вчера вообще где-нибудь на станции есть, или ночь потеряна и придётся ловить заново?»

По одной витрине на него не ответить. Витрина — конец ленты: здесь лежит РЕЗУЛЬТАТ счёта, а не исходные данные. Если строк за день нет, причин может быть несколько: источник ничего не прислал, данные приехали, но застряли по дороге, или не доехал только последний шаг.

Чтобы различить эти случаи, нужно пройти назад по ленте и проверить промежуточные полки.

Между приёмным портом и витриной стоят четыре полки. Один и тот же заказ на каждой выглядит по-разному, потому что меняется смысл строки.

Сегодня ты проходишь склад от конца к началу и для каждой полки отвечаешь на один и тот же вопрос: что здесь считается одной строкой.

Четыре стеллажа один за другим: россыпь карточек как приехали, те же карточки в типовых лотках, ящики с мелкими отсеками и одна светящаяся плита с пустой сеткой.
Груз один, а единица хранения на каждой полке своя — потому полок и четыре.
Перед тобой один заказ — №115725, обычный мартовский заказ — сразу на четырёх полках. Колонка rows_about_order показывает, сколько строк на каждой полке относятся к НЕМУ. Числа различаются, и это не ошибка загрузки: на каждой полке одна строка означает своё. Смотри на подпись смысла строки и две правые колонки; условие для витрины лишь находит город заказа, и его механику здесь разбирать не нужно.
Один и тот же заказ на четырёх полках: 0 строк в сыром слое, 2 в stg_orders, 3 в dds_fact_order_item, 1 в витрине. Меняется не груз, а смысл одной строки.

Полка — это обязательство, а не папка

Ноль, два, три, один. И всё это — один и тот же заказ.

Разница появилась не потому, что данные потерялись или размножились. Просто каждая полка хранит свой этап обработки, а значит, у каждой свой смысл строки.

Поэтому к любой таблице в этом курсе сначала задавай два вопроса: что означает одна строка и что эта полка обещает сохранить или исправить.

raw_orders — приёмный лоток. Здесь лежит то, что отдал порт, дословно: строка , время приёма, номер приёмной партии. Про мартовский заказ здесь ноль строк, потому что этот слой хранит НОЧЬ, а не историю: сегодняшний лоток к утру разберут и очистят.

Обязательство этой полки простое: «мы ничего не потеряли и ничего не переписали». Поэтому здесь не исправляют типы, не удаляют брак и не схлопывают дубли. Если начать «улучшать» сырой слой, при аварии уже не с чем будет сравнить следующие этапы.

stg_orders — разбор. Здесь тот же заказ уже разобран по колонкам: число стало числом, дата — датой. Строк две, потому что одна строка здесь означает не сам заказ, а загрузку заказа: ночью он приехал дважды, сначала как paid, потом как delivered.

Обязательство staging другое: «типы приведены, брак отложен в карантин, но история загрузок сохранена как есть». Мы уже можем работать с полями как с нормальными данными, но ещё не делаем вид, будто дублей и повторных версий не было.

dds_fact_order_item — стеллаж, с которого считают. Здесь одна строка — позиция заказа, поэтому строк три: в заказе три товара. Повторные загрузки и брак уже не размножают факты: у каждой позиции осталась одна строка.

Обязательство DDS: «одна строка = один факт, который можно анализировать в разных разрезах». Именно сюда идут, когда нужен новый аналитический вопрос, под который ещё нет готовой витрины.

dm_daily_revenue — витрина. Здесь одна строка — день × город. Наш заказ уже не виден отдельно: он растворился в одной агрегированной строке вместе с другими заказами этого города за день.

Обязательство витрины узкое: «быстро отвечаю на один заранее известный вопрос». Это удобно для отчёта, но цена удобства — потеря детализации. Если вопрос меняется, обычно возвращаются на DDS.

Отсюда следует и правило доступа: для отчётов используют витрину и DDS, а к сырому слою допускают только тех, кто обслуживает загрузку. Дело не в названии raw_*, а в качестве данных. Там намеренно лежат дубли, брак и мусор — всё то, что следующие полки должны разобрать и отфильтровать.

Отчёт по raw_* наследует все проблемы источника той ночи и обходит правила, ради которых вообще существует хранилище.

КВЕРИ: Отдай наружу сырой слой — и кто-нибудь непременно построит по нему отчёт. Потом Академия спросит, откуда в отчёте взялось то, что мы клялись дальше не пускать, и объясняться пойдёшь ты.

Теперь проверим смысл строки не по описанию, а запросом. Зададим один и тот же вопрос трём полкам и посмотрим, почему одинаковый COUNT(*) даёт разные по смыслу ответы.

Вопрос один: «сколько заказов было 12 марта». Колонка rows_in_day показывает, что вернёт наивный COUNT() по каждой полке. Колонка orders — правильное число заказов. Сравни две последние колонки: там, где одна строка означает не заказ, COUNT() отвечает уже на другой вопрос.

Словарь слоёв. Единственный раз за курс — дальше пользуемся, а не объясняем.

ЗдесьСинонимы, которые встретишь в вакансиях и чужом коде
raw_* — как приехалоraw, landing, bronze, «сырой слой»
stg_* — разобрано и типизированоstaging, ODS, silver, «операционный слой»
dds_* — факты и измеренияDDS, core, detail, «ядро хранилища»
dm_* — витрины под вопрос, CDM, gold, «слой отчётности»

Названий много, а смысл полок меняется гораздо реже. Поэтому не пытайся определить назначение слоя только по словам bronze, silver, ODS или CDM. Сначала выясни его обязательство и смысл одной строки.

На собеседовании обычно достаточно показать, что ты узнаёшь эти названия и понимаешь границы между соседними слоями: где данные ещё хранятся как приехали, где их разбирают, где лежат факты, а где — готовые ответы.

Количество слоёв бывает разным — наша лента живёт на четырёх. Дополнительный слой часто добавляют сверху под конкретную команду, чтобы её правки не трогали общее ядро.

Где песочница отличается от . В настоящем хранилище полки обычно разделяют схемами или даже базами: raw.orders, stg.orders, dds.fact_order_item. Тогда права можно выдавать на целую схему и, например, закрыть аналитикам сырой слой технически, а не договорённостью.

В нашей песочнице CREATE SCHEMA запрещён валидатором: иначе ученик смог бы уйти из своей изолированной схемы в чужую. Поэтому слой здесь обозначается ПРЕФИКСОМ имени таблицы: stg_orders вместо stg.orders.

Механика проще, но смысл тот же. Всё, что курс говорит про смысл строки, обязательства слоя и доступ, в проде переносится на схемы дословно.

Вопрос с собеседования

Как это спрашивают на собеседовании. «Зачем вам staging? Почему не грузить из источника сразу в витрину?»

Хороший ответ строится не вокруг «так принято», а вокруг трёх практических проблем ночной загрузки.

Первая — перезапуск. Если разбор и расчёт витрины слиты в один шаг, повтор снова идёт в источник. А источник за это время мог измениться. В итоге один и тот же вчерашний день при ретрае считается уже по другим входным данным.

Вторая — разбор аварии. Когда витрина врёт, нужно понять, где испортились данные: такими они приехали или ошибка появилась внутри хранилища. Для этого сравнивают сырой слой со staging. Если промежуточной полки нет, границу ошибки искать сложнее.

Третья — цена. Источник выгоднее прочитать и разобрать один раз, а уже из подготовленных данных строить несколько витрин.

После этого часто задают следующий вопрос: что означает одна строка вашей таблицы фактов? Здесь ответ должен быть коротким: одна строка — это позиция заказа, поэтому число заказов считается через COUNT(DISTINCT order_id), а не COUNT(*).

Есть два английских термина, которые стоит узнавать сразу. Смысл одной строки таблицы в отрасли называют grain. Полку «как приехало», где данные сохранены ровно в том виде, в каком их отдал источник, — raw layer.

Отвечать можно по-русски. Важно не слово, а то, что за ним стоит: какой смысл у строки и какое обязательство несёт слой.

Проверь себя
В stg_orders за 12 марта 1382 строки, а различных order_id — 1329. Каждый идентификатор встречается не больше двух раз. Что это значит?
Проверь себя
Продуктовая команда просит новый разрез: выручка по категориям товара за март. В витрине dm_daily_revenue категорий нет. К какой полке идти и почему?
Закрепление: реши задачи
Решено 0 из 3 · для зачёта достаточно 2
Главное из урока
  • Между портом и отчётом четыре полки: raw_* — как приехало, stg_* — разобрано, dds_* — факты и измерения, dm_* — витрина под конкретный вопрос.
  • Полка определяется не папкой и не названием, а обязательством и смыслом одной строки. Заказ №115725 занимает 0 строк в сыром слое (там живёт только сегодняшняя ночь), 2 в staging (две загрузки), 3 в DDS (три позиции), 1 из 1980 строк витрины.
  • Один и тот же вопрос «сколько заказов за 12 марта» даёт 1382, 3100 и 22 при наивном COUNT(*). Если считать именно заказы, на всех трёх полках получается 1329.
  • Поэтому COUNT(*) имеет смысл только после ответа на вопрос: что здесь означает одна строка.
  • Для отчётов используют витрину и DDS. К сырому слою допускают только тех, кто обслуживает загрузку: в нём намеренно лежит то, что следующие полки должны разобрать, отфильтровать или схлопнуть.
  • Чужие названия не меняют принцип: bronze/silver/gold, ODS, CDM — это другие слова для знакомых полок.

Теперь схема склада понятна. Дальше по ленте — первый участок, который ты соберёшь сам: приёмный порт. И начинается он с важного неудобства — источник отдаёт не таблицу.