Таблицы-контейнеры

Есть системы, где атрибуты сущностей на уровне базы данных сохраняются в, так называемые, таблицы-контейнеры.

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

Плюсы

  1. Сокращается количество таблиц.
  2. При добавлении новых атрибутов не требуется модифицировать схему базы данных.

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

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

Минусы

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

Много соединений — значит большая нагрузка на оптимизатор SQL (внутри СУБД). Особенно учитывая, что присоединяются не справочники, в которых значений мало, а таблицы-контейнеры, в которых записей больше чем в основной таблице. В итоге, СУБД не может оптимизировать план выполнения запроса.

Много записей — значит СУБД от блокировок строк переходит к блокировке таблицы или страниц данных. Это так называемая эскалация блокировок. Есть порог, после которого СУБД считает, что управлять большим числом блокировок строк дороже, чем малым числом блокировок таблиц или страниц.

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

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

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

Альтернативы

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

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