# Подход на основе только представлений для максимальной актуальности данных

Далее приведены примеры для Snowflake

На этой странице в примерах кода используется Snowflake, но подход на основе только представлений можно адаптировать и для других хранилищ данных.

Для некоторых рабочих нагрузок самый простой подход, наиболее близкий к работе «в реальном времени», — материализовать всё в виде представлений над непрерывно обновляемой исходной таблицей. Если преобразования очень легковесны, а источник уже обновляется почти в реальном времени, такой подход позволяет практически не увеличивать задержку источника.

## Когда использовать подход на основе только представлений

Используйте этот подход, если:

* Актуальность источника уже «достаточно хорошая» (например, сервис загрузки данных или операционная система записывает данные в таблицу хранилища каждые несколько секунд или минут).

* Преобразования очень легковесны, например:

  * Простой выбор или переименование столбцов
  * Одно-два соединения с небольшой справочной таблицей
  * Минимальное использование ресурсоёмких агрегаций или оконных функций либо их полное отсутствие

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

* Лучше всего этот подход подходит для небольших и средних таблиц с простыми запросами.

Типичные примеры:

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

Если логика преобразований становится сложнее, от данных зависят несколько команд или вам нужен более точный контроль затрат и производительности, переходите на [инкрементальные модели](https://docs.getdbt.tech/best-practices/how-we-handle-real-time-data/2-incremental-patterns.md) или [динамические таблицы / материализованные представления](https://docs.getdbt.tech/best-practices/how-we-handle-real-time-data/3-warehouse-native-features.md). Оставьте этот подход для самых небольших сценариев, наиболее чувствительных к задержке.

#### Предположения

Примеры на этой странице предполагают следующую конфигурацию:

* Внешняя по отношению к dbt система (ETL, потоковый конвейер, приложение) уже записывает данные в таблицу хранилища, например `raw.realtime_events` или `ops.active_sessions`, и эта таблица соответствует вашему соглашению об уровне обслуживания в части задержки.

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

* Вам не нужно, чтобы dbt сохранял промежуточные таблицы; для вас важны прежде всего:

  * Единообразная логика SQL (именование столбцов, приведение типов)
  * Тесты, контракты и происхождение данных
  * Exposures для BI-инструментов и других потребителей данных

Все модели dbt в этом подходе материализуются как представления, а не как таблицы или инкрементальные модели.

## Пример реализации

Ниже приведён пример реализации подхода на основе только представлений со следующей структурой:

* [Исходная таблица](#source-table-definition) (непрерывно обновляется): `raw.realtime_events`
* [Легковесное представление промежуточного слоя](#staging-view): `analytics.stg_realtime_events_v`
* [Представление предметной области](#domain-view-definition): `analytics.vw_realtime_events_enriched`

### Определение исходной таблицы

```yaml
# models/sources.yml
version: 2

sources:
  - name: raw
    schema: raw
    tables:
      - name: realtime_events
        description: "Непрерывно обновляемая таблица событий из потокового конвейера."
        loaded_at_field: event_ts
```

### Представление промежуточного слоя

```sql
-- models/staging/stg_realtime_events.sql
{{ config(
    materialized = 'view'
) }}

select
    event_id,
    event_ts::timestamp_ntz   as event_ts,  -- Синтаксис Snowflake для приведения типов
    to_date(event_ts)         as event_date,
    user_id,
    event_type,
    payload
from {{ source('raw', 'realtime_events') }};
```

### Определение представления предметной области

```sql
-- models/marts/vw_realtime_events_enriched.sql
{{ config(
    materialized = 'view'
) }}

with base as (
    select *
    from {{ ref('stg_realtime_events') }}
),

user_dim as (
    select
        user_id,
        user_segment,
        signup_date
    from {{ ref('dim_user') }}   -- может быть таблицей или инкрементальной моделью
)

select
    b.event_id,
    b.event_ts,
    b.event_date,
    b.user_id,
    u.user_segment,
    b.event_type,
    b.payload
from base as b
left join user_dim as u
  on b.user_id = u.user_id;
```

Инструменты-потребители запрашивают `analytics.vw_realtime_events_enriched`. Пока `raw.realtime_events` непрерывно обновляется, эта цепочка представлений обеспечивает ту же актуальность данных, что и источник.

## Преимущества

* Максимальная актуальность: представление отражает новые данные сразу после их поступления в `raw.realtime_events`.
* Простота эксплуатации: не нужно настраивать инкрементальную логику и запускать дополнительное задание dbt только ради поддержания актуальности данных. При этом задания для тестов, документации и других задач по-прежнему нужно запускать по расписанию.
* Оптимально для небольших наборов данных: подход хорошо работает с небольшими таблицами и простыми запросами. Вычисление представления на лету выполняется быстро и с небольшими затратами.

## Ограничения и риски

Этот подход безопасен только при соблюдении строгих условий и имеет несколько важных ограничений:

* [Не масштабируется для ресурсоёмких преобразований](#doesnt-scale-to-heavy-transformations)
* [Нет «зафиксированных» промежуточных таблиц](#no-frozen-intermediate-tables)
* [Чувствительность к изменениям схемы](#schema-change-sensitivity)
* [Возможное влияние на операционные системы](#potential-impact-on-operational-systems)

### Не масштабируется для ресурсоёмких преобразований

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

* Каждый запрос должен заново выполнять всю логику.
* Хранилищу приходится каждый раз оптимизировать и выполнять всю цепочку представлений.

В таких случаях используйте один из следующих вариантов:

* [Инкрементальные модели](https://docs.getdbt.tech/best-practices/how-we-handle-real-time-data/2-incremental-patterns.md)
* [Динамические таблицы или материализованные представления](https://docs.getdbt.tech/best-practices/how-we-handle-real-time-data/3-warehouse-native-features.md), если они подходят для вашей задачи

### Нет «зафиксированных» промежуточных таблиц

Поскольку всё реализовано в виде представлений:

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

### Чувствительность к изменениям схемы

Изменения схемы исходной таблицы немедленно распространяются по всей цепочке представлений, что:

* Может нарушить работу BI-инструментов, использующих эти данные, при удалении столбцов или изменении типов.
* Повышает важность тестов и контрактов моделей, поскольку нет границы между пакетными обработками, на которой можно обнаружить проблемы до того, как с ними столкнутся пользователи.

### Возможное влияние на операционные системы

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

1. Сначала реплицировать данные в таблицу хранилища (Snowflake, BigQuery, Databricks и т. д.).
2. Применять этот подход на основе только представлений внутри хранилища, а не непосредственно в системе оперативной обработки транзакций (OLTP).
