Перейти к основному содержимому

Оптимизация материализованных представлений с помощью dbt

· 10 мин. чтения
Amy Chen
примечание

Этот блог был обновлен 18 декабря 2023 года, чтобы охватить поддержку MVs на dbt-bigquery и обновления по тестированию MVs.

Введение

Год был 2020. Я жила в доме, где были только котята, а dbt Labs все еще называлась Fishtown Analytics. Один из корпоративных клиентов, с которым я работала, Jetblue, попросил меня помочь запускать их модели dbt каждые 2 минуты, чтобы соответствовать SLA в 5 минут.

После преодоления первоначального ужаса мы обсудили случай использования и вскоре поняли, что есть лучший вариант. Вместе с моей командой я создала lambda views, чтобы удовлетворить потребность.

Перенесемся в 2023 год. Я пишу это, пока мой огромный пес храпит рядом со мной (не волнуйтесь, коты тоже размножились). Jetblue переросла lambda views из-за ограничений производительности (представление может быть только настолько производительным), и мы находимся на очередной вехе в пути dbt к поддержке потоковой передачи. Какое время!

Сегодня мы объявляем, что теперь поддерживаем материализованные представления в dbt. Итак, что это значит?

Материализованные представления теперь являются готовой материализацией в вашем проекте dbt, как только вы обновитесь до последней версии dbt v1.6 на следующих адаптерах:

*Эти адаптеры поддерживали материализованные представления в своих адаптерах до версии 1.6.

Так же, как вы сегодня материализуете свою SQL-модель как table или view, вы можете использовать materialized_view в конфигурации вашей модели, dbt_project.yml и resources.yml файлах. На момент выпуска python модели не будут поддерживаться.

Для Postgres/Redshift/Databricks/Bigquery

{{
config(
materialized = 'materialized_view',
)
}}

Для Snowflake:

{{
config(
materialized = 'dynamic_table',
)
}}
примечание

Мы поддерживаем только динамические таблицы на Snowflake, а не материализованные представления Snowflake (для сравнения между Snowflake Dynamic Tables и Materialized Views, обратитесь к документации. Динамические таблицы лучше подходят для непрерывных преобразований благодаря функциональности, такой как возможность объединения, объединения и агрегации на базовых таблицах, представлениях и других динамических таблицах. Благодаря этим функциям они также больше соответствуют тому, что другие платформы данных называют материализованными представлениями. Для простоты, когда я упоминаю материализованные представления в этом блоге, я имею в виду динамические таблицы в Snowflake.

Теперь, когда мы поддерживаем материализованные представления: как вы интегрируете их в свой рабочий процесс dbt? Легко представить мир нерегулируемых вычислений, потому что вы не установили надлежащие ограничения, и теперь у вас есть материализованные представления, которые работают без вашего ведома на вашей платформе данных.

Материализованные представления, как и любая другая материализация, удовлетворяют потребность, и вы должны использовать их, учитывая дополнительную сложность, которую они добавят в ваш проект. Это инструмент в вашем наборе инструментов аналитической инженерии, один из многих.

В этом блоге мы рассмотрим, когда использовать этот инструмент, как успешно его использовать и как продвигать материализованные представления с учетом управления. Это новая функциональность, и я ожидаю, что это будет первый из многих постов, определяющих наши лучшие практики (или даже переопределяющих их). Также я не буду обсуждать взаимодействие dbt с платформой данных на более высоком уровне, например, как управлять вашими темами Kafka с помощью dbt, но настоятельно рекомендую этот пост от Чарли Саммерса, если это вас интересует.

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

Что такое материализованные представления?

Начнем с того, что такое материализованные представления (MVs)? Хотя конкретные функции могут различаться в зависимости от платформы данных, материализованные представления в своей основе являются объектами базы данных, которые хранят результаты запроса в виде физически материализованной таблицы. Что отличает их от обычной таблицы, так это то, что данные в материализованном представлении периодически обновляются, чтобы отражать последние изменения в базовой таблице. Поскольку они предварительно вычислены и результаты хранятся, вы получаете более быстрое время выполнения запросов при доступе к ним, потому что вы не пересчитываете данные с нуля. Это отлично подходит, когда у вас есть требования к низкой задержке для ваших конвейеров данных.

Теперь вы могли заметить, что MVs звучат очень похоже на инкрементные модели, и вы не ошибаетесь! Стоит рассматривать материализованные представления как своего рода преемника инкрементных моделей. Фактически, в зависимости от ваших потребностей и выбранной платформы данных, вы можете захотеть заменить все ваши инкрементные модели dbt на модели материализованных представлений. Делая это, вам больше не придется вручную разрабатывать конкретные инкрементные стратегии, подробно описывая, как dbt должен обновлять базовую таблицу. Здорово, правда?

Компромисс (помимо любых специфичных для платформы данных) заключается в том, что у вас будет меньше тонкого контроля над инкрементной логикой и оркестрацией. Это потому, что вы передаете определение логики того, что и как обновлять существующую таблицу, платформе данных, чтобы она выполняла это за вас.

Другие факторы, которые следует учитывать при принятии решения о том, когда/как использовать материализованное представление:

  • Каковы затраты, связанные с запуском материализованного представления по сравнению с пакетной инкрементной моделью? (это будет варьироваться в зависимости от вашей платформы данных, так как некоторые из них потребуют различных вычислительных узлов)
  • Поддерживает ли ваша платформа данных объединения, агрегации и оконные функции на MVs, если они вам нужны?
  • Каковы потребности в задержке вашей среды разработки? В производстве? (Если не в режиме реального времени, вы можете выбрать между пакетной инкрементной моделью или MV с более длительным расписанием обновлений.)
  • Как часто обновляются ваши вышестоящие зависимости? Если ваш ответ не часто, вам может не понадобиться MV.
  • Насколько велик ваш набор данных? (Может быть дешевле использовать MVs для очень больших наборов данных)
  • Как часто вам нужно обновлять ваш запрос? Каковы ваши нижестоящие зависимости и их заинтересованные стороны? (Если режим реального времени важен, MVs могут быть правильным выбором).
  • Есть ли у вас модели машинного обучения в реальном времени или приложения, использующие ваш преобразованный набор данных?

Материализованные представления в рабочем процессе dbt

Разработка

Когда мы говорим об использовании материализованных представлений в разработке, вопрос, который стоит обдумать, заключается не столько в том, "должны ли вы выполнять свои модели dbt как материализованные представления в своей песочнице?", сколько в том, "должны ли вы планировать их обновление в своей песочнице?". Для разработки вам нужно создать их и протестировать в своей песочнице, но как сделать это так, чтобы не увеличивать счет за облачные услуги? Или не оставлять стикер на вашем ноутбуке с напоминанием удалить все работающие материализованные представления в вашей песочнице перед тем, как выйти? Давайте поговорим об этом!

Помимо части планирования, разработка будет довольно стандартной. Ваш конвейер, вероятно, будет выглядеть примерно так:

Конвейер в реальном времениКонвейер в реальном времени

Это предполагает, что у вас есть конвейер почти в реальном времени, где вы извлекаете данные из потокового источника данных, такого как Kafka Topic, через инструмент загрузки по вашему выбору, например, Snowpipe для потоковой передачи в вашу платформу данных. После того, как ваши данные находятся на платформе данных, вы:

  1. Создайте модель dbt с необходимой логикой преобразования SQL.
  2. Посмотрите на логику и ответьте на эти вопросы:
    1. Поддерживает ли моя платформа данных функциональность, которая мне нужна в материализованных представлениях?
    2. Как часто вам нужно обновлять данные? Нужна ли вам какая-либо гибкость в этом?
    3. Как я продвигаю это в производство? Либо вы будете запускать логику преобразования в производственной среде (рекомендуется) и создавать отдельный объект, либо продвигать объект, созданный в процессе разработки.

В зависимости от вашего ответа, это решит, хотите ли вы материализованное представление в первую очередь (в отличие от представления, таблицы или инкрементной модели). Если вы решили, что материализованное представление соответствует вашим потребностям, по умолчанию не планируйте обновление. Вы можете выполнять ручные обновления по мере необходимости. Почему так? В вашей среде разработки вы, вероятно, проверяете три вещи: зависимости, логику SQL и результат преобразования. Все это можно протестировать, создав материализованное представление без планирования и выполняя ручные обновления.

Ваша конфигурация во время разработки:

Для Postgres:

Каждый раз, когда вы выполняете dbt run, это приведет к ручному обновлению, если вы не установите on_configuration_change в continue, что пропустит выполнение модели.

{{
config(
materialized = 'materialized_view',
on_configuration_change = 'apply',
)
}}

Для Redshift:

{{
config(
materialized = 'materialized_view',
on_configuration_change = 'apply',
auto_refresh = False
)
}}

Для Bigquery

{{
config(
materialized = 'materialized_view',
on_configuration_change = 'apply',
enable_refresh = True,
refresh_interval_minutes = 30
max_staleness = 'INTERVAL 60 MINUTE'
)
}}

Для Databricks:

{{
config(
materialized='materialized_view',
)
}}

По умолчанию, материализованные представления не обновляются по расписанию на Databricks в этой материализации. Чтобы настроить расписание, вы можете использовать post-hook для изменения MV с расписанием cron, которое будет выполняться в Databricks Workflows. Это может выглядеть примерно так:

post_hook = 'ALTER MATERIALIZED VIEW {{this}} ADD SCHEDULE CRON "0 0 0 * * ? *" AT TIME ZONE "America/Los_Angeles";'

Для Snowflake:

{{
config(
materialized = 'dynamic_table',
snowflake_warehouse = '<warehouse>',
target_lag = '<desired_lag>',
on_configuration_change = 'apply',
)
}}

Теперь, если вам нужно более полно построить ваш конвейер разработки (убедившись, что планирование/синхронизация действительно происходят), вы можете запланировать, но убедитесь, что удаляете материализованные представления, когда закончите с ними. Я призываю вас инвестировать в макрос операций, который удаляет все MVs в схеме, которую вы используете в качестве своей песочницы, и запускать его по мере необходимости. Вы даже можете создать задание dbt Cloud для управления этим. Таким образом, у вас не будет никаких случайных MVs, работающих в вашей песочнице, потребляющих кредиты без необходимости.

Тестирование

Теперь давайте углубимся во второй вопрос: как тестировать? В разработке и QA это будет выглядеть так же, как и любые тесты, которые у вас могут быть при разработке ваших пакетных конвейеров. Вы можете запустить dbt build или dbt test, а затем тесты будут выполняться после выполнения в качестве проверки. Но что меняется в производстве?

Я рекомендую обновить любые тесты, применяемые к материализованному представлению/динамической таблице, с конфигурацией store_failures_as, установленной в true и материализованной как представление. Это позволяет создать представление, которое будет предоставлять все строки, которые не прошли ваш тест на момент запроса. Обратите внимание, что это не предоставляет исторический обзор. Вы также можете создать оповещения на представление, если оно не соответствует вашим ожиданиям.

Чтобы продвигать материализованные представления в производство, процесс будет выглядеть так же, как и с вашими инкрементными моделями. Используйте CI jobs с defer, чтобы вы могли встроить их в вашу среду QA. Для существующих MVs без изменений мы можем пропустить и отложить до производственных объектов.

Производство

Когда вы будете удовлетворены своей разработкой и тестированием, для платформ данных, которые предлагают планирование через наши конфигурации dbt, у вас есть два варианта: жестко закодировать частоту обновления или написать условную логику на основе среды для частоты обновления. Я рекомендую использовать последний вариант.

Код для включения условия в ваш блок конфигурации выглядит так, если вы хотите включить в макрос для либо задержки, либо других полей (snowflake_warehouse, auto_refresh и т.д.):

{% macro target_lag_environment() %}
{% set lag = '1 minute' if target.name == "prod" else '35 days' %}
{{ return(lag) }}
{% endmacro %}
{{
config(
materialized = 'dynamic_table',
snowflake_warehouse = 'transforming',
target_lag = target_lag_environment(),
on_configuration_change = 'apply',
)
}}

Вы захотите очень долгую задержку для разработки; я рекомендую частоту, с которой вы удаляете и обновляете вашу среду разработки. Здесь я просто выбрала свои два любимых числа.

Для оркестрации, если ваши материализованные представления не могут автоматически обновляться, вы можете использовать dbt cloud для оркестрации ваших обновлений. Прелесть материализованных представлений в том, что dbt сможет предоставить зависимость/тестирование/документацию, а также пропустить или повторно выполнить модели в соответствии с конфигурацией, позволяя вам версионировать вашу логику. Разумные ограничения для современной стек данных. ✨

В зависимости от того, как вы оркестрируете свои материализованные представления, вы можете либо запускать тестирование в производстве в рамках запланированного задания (с dbt test или dbt build).

Заключение

Ну что ж, я рада, что все вы сможете удалить строки в вашем packages.yml, которые устанавливали ваш экспериментальный пакет (по крайней мере, если вы используете его для MVs) и начать погружаться в работу. Мы все еще находимся в начале нашего пути, и я с нетерпением жду, чтобы услышать о всех вещах, которые вы создаете, и о том, как мы можем улучшить наши лучшие практики в этом.

Comments

Loading