Как стать автором
Обновить
135.89
Холдинг Т1
Многопрофильный ИТ-холдинг

Методы расширения атрибутивного состава таблиц БД

Уровень сложностиСредний
Время на прочтение11 мин
Количество просмотров1.4K

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

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

Сразу отмечу, что решения и оценки, о которых пойдёт речь, подбирались для работы с большими данными на стеке технологий Apache Hadoop, где для обработки данных использовали фреймворк Apache Spark, СУБД — Apache Hive для анализа данных, оркестратор — AIRFLOW, данные хранятся в колоночном формате Parquet.

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

В SQL изменение существующих записей и структуры таблиц в БД является фундаментальной операцией. Однако при работе с большими данными в Hadoop операция по изменению записей (update) отсутствует, для изменения ранее записанных данных приходится прилагать усилия, перезаписывая полностью файлы Parquet: сначала Spark читает в dataframe (select) и изменяет данные (filter/union/...), потом либо записывает во временную таблицу (write), либо кеширует dataframe (cache), и в конце перезаписывает таблицы или партиции (insertInto с параметром overwite. То есть, вместо одной операции update выполняется пять.

Для изменения структуры таблицы в Hadoop чаще всего выполняются аналогичные действия, только после шага write/сache таблица перезаписывается вместе со схемой ( saveAsTable с параметром overwite). Этот метод подходит для небольших таблиц. А когда объёмы достигают сотни гигабайтов, перезапись становится ресурсозатратной и приходится задумываться о более оптимальном варианте изменения структуры таблицы.

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

Решение 1. Добавление атрибутов методом EAV (Entity-Attribute-Value)

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

Пример классической модели EAV. БД из трёх таблиц: «Сущностей», «Атрибутов» и «Значений».
Пример классической модели EAV. БД из трёх таблиц: «Сущностей», «Атрибутов» и «Значений».

В проекте уже была создана табличная структура с фиксированными атрибутами. Сущности EAV — attribute и value — объединены в одной таблице, поэтому необходимо было модифицировать классический EAV‑метод. Также учитывалось, что в Hive операция join является ресурсозатратной и замедляет выполнение запросов, особенно при работе с большими объёмами данных. Размер таблиц достигал сотен гигабайтов, что требовало сократить количество взаимосвязей между ними.

Мы разработали единую динамическую таблицу, объединяющую все три сущности классической модели EAV. Состав таблицы включал в себя 8 атрибутов: 

Атрибут

Тип атрибута

Наименование

1

data_id

string

ИД среза данных

2

id

string

ИД записи

3

object_name

string

Наименование сущности — таблицы

4

attr_name

string

Наименование атрибута

5

attr_string

string

Значение атрибута формата строки

6

attr_int

integer

Значение атрибута формата целого числа

7

attr_decimal

decimal(36,6)

Значение атрибута формата нецелого числа

8

attr_date

date

Значение атрибута формата даты

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

Пример соединения таблицы с фиксированными атрибутами и динамической таблицы
Пример соединения таблицы с фиксированными атрибутами и динамической таблицы

В таблице соблюдались требования, согласно которым атрибуты должны иметь четыре возможных типа данных. При записи данных значения атрибута складывались в поле соответствующего ему типа attr_string, attr_int, attr_decimal или attr_date, и при чтении атрибут в dataframe создавался в соответствии с типом поля, из которого был взят.

При создании полноценной линейной таблицы динамическая таблица транспонировалась и объединялась (join) с ранее созданной таблицей по идентификаторам data_id и id. Обе таблицы были партиционированы по атрибуту data_id.

Запросы строились через партиции. Объединение (join) происходило именно по партициям, что значительно сокращало время выполнения операций. Перед объединением использовалась фильтрация динамической таблицы по object_name, что позволяло исключить данные сущностей, не участвующих в объединении. Также для оптимизации количества данных динамической таблицы атрибуты с null‑значениями не записывались.

Основные преимущества решения:

  • Данные хранятся в едином месте.

  • «Старые» таблицы не разрастаются, остаются в текущем виде.

  • При добавлении новых сущностей структура динамической таблицы не изменяется.

  • Динамическая таблица может хранить неограниченное количество сущностей.

Основные недостатки решения:

  • Разрастание динамической таблицы по формуле (количество добавленных записей в основной таблице * количество новых атрибутов).

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

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

  • Для пользовательской работы с таблицей необходимо создавать view.

Решение 2. Добавление атрибута типа JSON в таблицы

Формат JSON не поддерживается в Hive, поэтому атрибут создается с типом данных string, но по структуре напоминает JSON. В Hive тип данных string не имеет ограничения по количеству символов, при этом, максимальный объём данных поля string составляет 2 Гб (2 147 483 647 байтов).

Добавление атрибута типа JSON в DDL таблиц происходит единожды функцией alter_table через метаданные Hive. При обращении к ранее записанным данным атрибут JSON заполняется значением null.

Пример добавления в фиксированный набор атрибутов таблицы атрибута типа json
Пример добавления в фиксированный набор атрибутов таблицы атрибута типа json

Новые атрибуты в  json_attr151 записывались таким образом:

[
  {
    "attr_name": "id",
    "attr_value": "1",
    "attr_type": "string"
  },
  {
    "attr_name": "cost",
    "attr_value": "100",
    "attr_type": "int"
  }
…
]

Value в json записываются в унифицированном формате string, и уже после чтения преобразуются в формат, указанный в attr_type. Наименование атрибута содержит поле attr_name, а значение атрибута — поле attr_value.

Такой формат хранения универсальный и высокопроизводительный, нет необходимости использовать дополнительные соединения таблиц (join). Для чтения и записи новых атрибутов достаточно использовать JSON‑схему, содержащую актуальный набор дополнительных атрибутов, хранящихся в json.

Основные преимущества решения:

  • Поле типа json обладает большой вместимостью и не требует больших ресурсов хранения.

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

  • Отсутствуют дополнительные соединения таблиц.

  • В структуру таблиц добавляется только один полноценный атрибут.

Основные недостатки решения:

  • Необходимо поддерживать актуальную JSON‑схему для чтения и записи новых атрибутов.

  • Сложность в алгоритмах работы с JSON.

  • Для пользовательской работы с таблицей необходимо создавать view.

  • Появление атрибутов с уникальными значениями негативно влияет на сжатие данных.

Решение 3. Добавление атрибутов командой  alter table cascade 

В Hive команда alter table cascade используется для изменения схемы таблицы, например добавления нового столбца, изменения имени столбца, переименования таблицы и т. д. Изменения затрагивают метаданные таблицы, при этом сама структура данных в HDFS остаётся неизменной. Во время чтения или записи расхождение данных и метаданных таблицы приведёт к ошибке. С такими ограничениями операции по удалению и переименованию атрибутов становятся ресурсозатратными, вслед за изменением метаданных таблицы требуется полностью переписать данные под новую структуру. Перезапись сотен гигабайтов требует больших вычислительных ресурсов кластера и занимает продолжительное время, поэтому мы решили только добавлять атрибуты в БД. После добавления новых атрибутов в метаданные, во время чтения таблицы ранее записанные строки заполняются null‑значениями и не вызывают ошибок.

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

Пример добавления в таблицу атрибута методом  alter table cascade через метаданные Hive (атрибут  attr151)
Пример добавления в таблицу атрибута методом  alter table cascade через метаданные Hive (атрибут  attr151)

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

Основные преимущества решения:

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

  • Можно добавлять большое количество атрибутов без значительной потери производительности.

  • Чтение и запись в таблицу осуществляются простыми функциями select и insert.

  • Таблица имеет линейную структуру, удобную для работы пользователей.

  • Не требуется создавать view.

Основные недостатки решения: таблица увеличивается в ширину — становится визуально сложно читать данные.

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

Для анализа увеличения объёмов данных таблицы от добавления новых атрибутов мы создали таблицу table, данные в которой по содержанию и структуре аналогичны промышленным. Состав таблицы — 630 тыс. записей и 122 атрибута, объём — 126 Мб (одна партиция). Расширили таблицу сотней атрибутов по двум сценариям: с уникальными значениями и с повторяющимися значениями.

EAV

Как показано на рисунке 2, дополнительно создавали динамическую таблицу dynamic_table. Идентификатор Data_id в обеих таблицах имел одно значение, обозначающее срез данных. Идентификатор ID был уникальным, то есть всего было 630 тыс. уникальных записей.

В первом сценарии уникальные значения записывались в attr_string для всех 100 новых атрибутов. Размер таблицы составил примерно 363 мегабайта. Для каждого нового атрибута в динамической таблице создавалось 650 тыс. записей. В результате в таблице набралось 65 млн записей.

Для реализации второго сценария мы случайным образом отобрали сто атрибутов из таблицы table. Они включали в себя уникальные идентификаторы, продуктовые разметки и пользовательскую информацию, то есть полное разнообразие атрибутов, ожидаемое при реальном расширении атрибутивного состава. Новые атрибуты распределили по соответствующим их типам данных атрибутам динамической таблицы attr_string, attr_int, attr_decimal и attr_date. Записи с null‑значениями исключали из таблицы, и в результате размер её составил примерно 213 мегабайтов.

JSON

Командой alter table cascade добавили поле типа json и наполнили его сотней новых атрибутов.

В первом сценарии размер таблицы увеличился примерно на 160 килобайтов.

Во втором сценарии размер таблицы увеличился примерно на 58 мегабайтов.

Для реализации сценариев мы алгоритмически записали сто новых атрибутов строкой в поле json. Value json в соответствии с примером заполняли наименованием атрибута — attr_name, значением атрибута — attr_value, и типом данных атрибута — attr_type.

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

Alter table

В таблицу table добавили сто атрибутов методом  alter table. Для начала заполнили их уникальными значениями по первому сценарию. Размер таблицы увеличился на 529 Мб новых данных. 

Для реализации второго сценария создали view основной таблицы, случайным образом отобрали сто атрибутов и объединили (join) по уникальному идентификатору с основной таблицей. Эти новые атрибуты содержали уникальные идентификаторы, продуктовые разметки и пользовательскую информацию, то есть полное разнообразие атрибутов, ожидаемое при реальном расширении атрибутивного состава. В результате, с учётом сжатия Parquet, размер таблицы увеличился на 101 мегабайт.

Результаты увеличения объема данных в таблицах:

EAV

JSON

Alter table cascade

Повторяющиеся значения

213 Мб

160 Кб

101 Мб

Уникальные значения

363 Мб

58 Мб

529 Мб

Тестирование метода  alter table cascade показало среднюю ресурсозатратность на хранение данных, эффект сжатия формата Parquet оптимизировал объём данных примерно в 5 раз.

Самую высокую ресурсозатратность на хранения данных показал метод EAV, динамическая таблица разрослась до 65 млн записей. Формат Parquet сжал атрибуты  Deal_ID (650 тыс. уникальных записей),  IDobject_name (1 уникальная строка),  attr_name (сто уникальных строк) в обоих сценариях. Сжатие атрибутов  attr_stringattr_intattr_decimal и  attr_date произошло только во втором сценарии, за счёт повторяющихся значений объём хранения данных уменьшился в 1,7 раза.

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

Оценка

Для оценки наиболее подходящего метода мы отобрали метрики, учитывающие ключевые особенности проекта:

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

  2. Сложность чтения данных. Операции чтения, даже с учётом партиционирования, требуют больших вычислительных ресурсов. Усложнение алгоритмов могло привести к увеличению времени пользовательских расчётов. 

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

  4. Необходимость создания визуализации типа external table. Таблицы необходимо было использовать в горизонтальном формате для решения аналитических задач. 

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

  6. Разрастание таблицы. У Hive нет проблем с хранением нескольких тысяч атрибутов, однако время работы с такой таблицей увеличивается, и при недостатке ресурсов появляются ошибки хранения данных в оперативной памяти. 

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

Оценивали командой по трёхбалльной шкале:

Оценка

Балл

Лёгкое/минимальное

3

Среднее 

2

Сложное/большое

1

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

Метод/метрика

Объём хранимых данных

Чтение данных

Запись данных

Создание визуализации

Работа с таблицей

Разрастание DDL таблицы

Алгоритмическая сложность

Результат оценки

Добавление атрибута типа json

Минимальное

Среднее

Среднее

Среднее

Среднее

Среднее

Среднее

15

EAV (Entity-Attribute-Value)

Большое

Сложное

Сложное

Среднее

Сложное

Минимальное

Сложное

10

Добавление командой alter table cascade

Среднее

Легкое

Легкое

Легкое

Легкое

Большое

Легкое

18

Выводы

Результаты исследования показали, что каждый из подходов имеет свои достоинства и недостатки, и допустимо было решить поставленную задачу любым подходом. Однако наиболее оптимальное решение для текущего проекта — использование метода alter table cascade для таблиц с фиксированным количеством атрибутов. Как отмечалось, метод лёгкий в реализации и полностью учитывает потребности пользователей в использовании витрин данных. А какой метод подошёл бы для вашего проекта?

Теги:
Хабы:
+6
Комментарии1

Публикации

Информация

Сайт
t1.ru
Дата регистрации
Дата основания
Численность
свыше 10 000 человек
Местоположение
Россия
Представитель
ИТ-холдинг Т1