Три полки: raw → stg → DDS → витрина
Чему научишься
- видеть между источником и отчётом четыре полки, а не одну стрелку
- для каждой полки объяснять, что означает одна строка, и проверять это запросом
- отвечать на вопрос «сколько было заказов» так, чтобы ответ зависел от смысла полки, а не от удачного
COUNT(*) - читать чужие названия слоёв: raw/stg/DDS/витрина, bronze/silver/gold, ODS/CDM — за разными словами часто стоит один и тот же склад
Тикет №01, часть вторая. «А данные-то целы?»
09:20. Ты ответил в Академию: за 14-е витрина не досчитана, за 13-е посчитана дважды. Через минуту приходит новый вопрос:
«Понял. А сами данные целы? Заказы за вчера вообще где-нибудь на станции есть, или ночь потеряна и придётся ловить заново?»
По одной витрине на него не ответить. Витрина — конец ленты: здесь лежит РЕЗУЛЬТАТ счёта, а не исходные данные. Если строк за день нет, причин может быть несколько: источник ничего не прислал, данные приехали, но застряли по дороге, или не доехал только последний шаг.
Чтобы различить эти случаи, нужно пройти назад по ленте и проверить промежуточные полки.
Между приёмным портом и витриной стоят четыре полки. Один и тот же заказ на каждой выглядит по-разному, потому что меняется смысл строки.
Сегодня ты проходишь склад от конца к началу и для каждой полки отвечаешь на один и тот же вопрос: что здесь считается одной строкой.

rows_about_order показывает, сколько строк на каждой полке относятся к НЕМУ. Числа различаются, и это не ошибка загрузки: на каждой полке одна строка означает своё. Смотри на подпись смысла строки и две правые колонки; условие для витрины лишь находит город заказа, и его механику здесь разбирать не нужно.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(*) даёт разные по смыслу ответы.
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 категорий нет. К какой полке идти и почему?- Один к одному, один ко многимEASY
- Размножение строк после JOINEASY
- Количество строк после DISTINCT поверх GROUP BYEASY
Главное из урока
- Между портом и отчётом четыре полки:
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 — это другие слова для знакомых полок.
Теперь схема склада понятна. Дальше по ленте — первый участок, который ты соберёшь сам: приёмный порт. И начинается он с важного неудобства — источник отдаёт не таблицу.