Сегодня BI-аналитика немыслима без ETL. Просто физических джоинов уже не хватает — чаще нужны логические модели данных. Они позволяют создавать сложные структуры без необходимости вручную писать запросы. Tableau, как self-service инструмент, дал такую возможность, представив в 2020-м релейшены (relationships), которые сделали модели данных более гибкими и производительными. А совсем недавно появились мультифакторные релейшены (multi-fact relationships), о которых и поговорим.

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

Именно с такой задачей мы недавно столкнулись при анализе ассортимента торговой сети.

Посмотрим на структуру данных: 

  1. Продажи находятся в таблице Orders

  2. Остатки — в таблице Inventory

  3. Категории и описания товаров — в таблице Products

  4. Названия торговых точек — в таблице Stores.

Так выглядят связи таблиц
Так выглядят связи таблиц

Бизнес-задача: выявить неликвидные товары в разных категориях.

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

Склад здесь — это конкретная торговая точка. В отчете надо было представить продажи и остатки товаров в разрезе категорий. Важно включить сравнение показателей с предыдущим периодом, чтобы отследить динамику. Также на дашборде должен быть фильтр по названию торговой точки для более точного анализа. 

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

Разработчики обычно используют 3 основных подхода: 

  1. Работа с релейшенами на логическом уровне.

  2. Сочетание джойнов на физическом уровне с релейшенами на логическом уровне.

  3. Внесение доработок на уровне базы данных. 

Логические и физические уровни модели данных в Tableau. База

Модель данных Tableau может быть построена на двух различных уровнях: логическом и физическом. Разница между ними в том, как связаны таблицы.  

При объединении физических таблиц формируется один SQL-запрос и возвращается одна итоговая результирующая таблица. При этом в Tableau нам не нужно писать сам запрос, только «перетащить» таблицу в модель данных.  

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

1. Работа с релейшенами на логическом уровне 

Самый простой вариант — создание модели типа «звезда» при помощи релейшенов. Присоединим к фактовой таблице Orders фактовую таблицу Inventory и справочник Products.

Модель данных «звезда»
Модель данных «звезда»

Сначала посмотрим на исходные данные.

Теперь посмотрим, как при такой связи Tableau выводит данные, и подходит ли это для нашей бизнес-задачи. 

Поскольку товар №7 не продавался, строки с ним нет в таблице заказов. Довольно типичная ситуация — не по всем товарам из ассортимента должны быть продажи. Т.е. таблицу Заказов нельзя использовать как основную в модели, ведь она не отражает весь перечень продуктов. И если связи в модели будут проходить через нее, Tableau просто не увидит данные по отсутствующему товару в связанной таблице (Inventory) и не выведет их.

Все товары есть в таблице Inventory. Но ее мы тоже не можем использовать как главную, потому что тогда в слепой зоне у нас окажется, например, товар №6. По нему были продажи, но его нет в наличии. Соответственно, сделав главной таблицей Inventory, аналогично получим некорректный результат. 

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

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

Но как быть, если у нас несколько справочных таблиц, которые относятся как к таблице Orders, так и к таблице Inventory?

2. Сочетание джойнов на физическом уровне с релейшенами на логическом уровне

В качестве решения можно объединить некоторые таблицы на физическом уровне, например, Orders и Inventory, а затем связать их с Products и Stores.

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

Потенциальная проблема 1: замножение данных 

Таблица Orders содержит данные на уровне транзакции (максимальная детализация — Order_ID). Остатки же агрегированы за день для каждого продукта и магазина (Product_ID, Store_ID, Date). Прямое их сопоставление, например, с помощью Product_ID, Store_ID и даты, может привести к замножению данных, когда для каждого заказа дублируется количество товаров на остатке. 

Потенциальная проблема 2: конфликт фильтров   

Фильтрация на дашборде влияет на обе таблицы одновременно. Однако фильтры, применяемые к одной таблице, могут не иметь смысла для другой (например, фильтрация по Order_date или Order_ID неприменима к остаткам). 

Потенциальная проблема 3: потеря производительности  

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

В качестве альтернативы мы могли бы объединить справочники Products и Stores, чтобы создать единую таблицу измерений, а затем связать ее с фактовыми таблицами Orders и Inventory

Для того чтобы исключить потерю данных, нужно выполнить full outer join по связке калькулируемых полей 1=1, то есть фактически cross join.

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

3 Внесение доработок на уровне базы данных

Этот подход обеспечивает более высокую производительность благодаря агрегации данных и материализации вычислений. Однако он ограничивает self-service и возвращает нас в предыдущее поколение BI, когда аналитики сначала создают на стороне СУБД представление и только потом приступают к собственно аналитике.

Подводя итог, что можно сказать о каждом варианте:

1. При использовании релейшенов возможна потеря данных.

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

3. Внесение доработок на уровне БД отдаляет нас от self-service.

Новое решение: мультифакторные релейшены 

Еще недавно мы не могли создать в Tableau модель данных с несколькими фактовыми таблицами. Версия Tableau 24.2 представила более эффективное решение для таких случаев — multi-fact relationships.

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

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

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

Как работают мультифакторные релейшены 
Как работают мультифакторные релейшены 

При помощи мультифакторных релейшенов мы наконец получаем желаемый результат: 

Еще одна отличная новость: не все базовые таблицы должны быть связаны со всеми таблицами измерений. Можно добавить справочник покупателей Customers, который будет связан только с таблицей Orders. Кроме того, пересекающиеся таблицы могут быть связаны с последующими таблицами. Например, к таблице Customers можно добавить связь с таблицей Regions.

Сравнение производительности

Посмотрим на производительность двух решений.

Первая модель данных использует сочетание джойнов на физическом уровне с релейшенами на логическом уровне (подробно рассмотрели выше), а вторая модель — мультифакторные релейшены.  

Сравнивать производительность будем на примере следующей визуализации: данные о продажах и остатках за выбранный день в сравнении с предыдущим днем (таблицы Sales и Inventory, соответственно), разбитые по категориям товаров из (таблица Products), а также отфильтрованные по названию торговой точки (таблица Stores).

С каким объемом данных работаем? Таблицы Sales и Inventory содержат порядка 30 тыс. строк каждая, таблица Products содержит 1 850 строк, а таблица Stores всего 10 строк. 

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

Загрузка визуализации, построенной на модели, использующей сочетание джойнов и релейшенов, заняла у Tableau 0.35 секунды

Оцениваем скорость загрузки модели с сочетанием джойнов и релейшенов
Оцениваем скорость загрузки модели с сочетанием джойнов и релейшенов

Загрузка визуализации, использующей мультифакторную модель заняла у Tableau в два раза меньше времени — 0.18 секунды.

Через Executing Query видим, как Tableau генерирует запросы к источнику данных. И видим, что негативно влияет на производительность дашборда.  

Запрос, сгенерированной на модели джойнов и релейшенов: 

И запрос, сгенерированный на мультифакторной модели: 

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

  • В первом запросе данные из таблицы Inventory запрашиваются и обрабатываются дважды: один раз для вычисления метрик и еще раз для объединения с дополнительными таблицами. Во втором запросе агрегация и объединение выполняются в рамках одного подзапроса, что упрощает обработку данных. 

  • Первый запросе содержит избыточный cross join, создающий декартово произведение таблиц Products и Stores. Каждая строка из таблицы Products соединяется с каждой строкой из таблицы Stores (1 850*10=18 500 строк). Во втором запросе cross join отсутствует, что делает его более эффективным. 

Заметим, что первый запрос был сформирован для вывода всего двух метрик на визуализации: остатков за текущий и за предыдущий период. Параллельно был сформирован аналогичный запрос для отображения продаж. Поскольку количество таких запросов пропорционально числу визуализаций на дашборде, использующих поля из справочных таблиц, это может еще больше замедлить дашборд. В каждом запросе Tableau будет обрабатывать бОльший объем данных, чем если бы обращался к каждой из справочных таблиц по отдельности.

Использование мультифакторной модели позволило ускорить дашборд в 2 раза!

Мультифакторные релейшены в Tableau 24.2 стали настоящим прорывом для работы с моделями данных, содержащими несколько фактовых таблиц. 

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

  • подключать несколько фактовых таблиц к общим справочникам; 

  • корректно обрабатывать данные из фактовых таблиц с разной детализацией; 

  • значительно ускорять обработку запросов и визуализацию.

Сравнение производительности показало, что новая модель позволяет вдвое сократить время загрузки дашбордов и оптимизировать запросы к данным. Теперь аналитики могут создавать гибкие, сложные и производительные модели, не теряя преимущества self-service BI. 

Подробнее про то, как работает мультифакторная модель, ее плюсах и минусах, смотрите наше техревью.

Комментарии (5)


  1. shadowjack
    20.12.2024 15:49

    релейшены (relationships)

    мультифакторные релейшены (multi-fact relationships)

    Так релейшены (relations), или релейшоншипы (relationships)? Вы уж определитесь. Между тем, у обоих слов есть вполне устоявшийся в русскоязычной технической литературе перевод:

    Куликов С., "Реляционные базы данных в примерах"
    Куликов С., "Реляционные базы данных в примерах"


    1. radachynskaja Автор
      20.12.2024 15:49

      Здравствуйте! Имеются в виду relationships, просто среди разработчиков их для упрощения зовут релейшенами.


      1. shadowjack
        20.12.2024 15:49

        А давайте вы будете для написания технических публикаций использовать правильную терминологию?

        А что и как там вы и ваши малограмотные коллеги зовут для упрощения -- это неважно.


    1. mentin
      20.12.2024 15:49

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

      Хотя я бы предпочел, скажем, таблицы фактов и связи с множественными фактами.


  1. Ivan22
    20.12.2024 15:49

    и все-таки для взрослого решения, переиспользуемого в разных отделах нашего огромного энтерпрайза, необходимо минимизоровать все расчеты и джоины на уровне репортинга и делать все расчеты в витрине в DWH