Многопользовательская БД: зачем ставить столбец TenantID в каждой таблице? - PullRequest
14 голосов
/ 16 ноября 2009

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

zoos
-------
id
zoo_name
tenant_id

animals
-------
id
zoo_id
animal_name
tenant_id

Однако, это кажется мне излишним. Почему бы не добавить столбец tenant_id в таблицу zoos и использовать отношение внешнего ключа между zoos и animals?

Вы добавляете tenant_id к каждому столу только для того, чтобы соединения не становились слишком сумасшедшими? Это защита от ошибок? Оценка производительности?

Ответы [ 6 ]

14 голосов
/ 16 ноября 2009

Если одним из ваших ключевых соображений при проектировании является безопасность - в частности, один клиент не может никоим образом не получить доступ к данным другого клиента - тогда, в зависимости от того, как вы реализуете эту защиту, вставка соответствующего столбца в каждую таблицу может быть необходимо. Одна такая тактика, описанная здесь , требует построения представления на каждом столе; при условии, что каждая таблица содержит столбец tenantId, тогда при правильной настройке каждое представление может содержать предложение «WHERE tenantId = SUSER_SID ()» (и, конечно, вы настраиваете базу данных так, чтобы клиенты могли иметь доступ только к представлениям).

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

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

9 голосов
/ 16 ноября 2009

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

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

См. Эту статью Возможно, нормализация не является нормальной - и ее вывод:

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

как место для начала изучения предмета

8 голосов
/ 17 ноября 2009

Если у меня есть tenantID на вершине иерархии (т. Е. На уровне зоопарка), у вас есть несколько вопросов для рассмотрения.

  1. Вершина иерархии никогда не изменится, например, если вам нужно добавить узел на дереве выше уровня зоопарка (скажем, регионы -> зоопарки -> животные), тогда она будет каждый раз вызывать повторную организацию. 1004 *
  2. Для определенных запросов вы будете вынуждены начинать с вершины иерархии, т.е. дать мне список всех доступных животных, которые заставят вас начинать с вершины дерева
  3. Почему бы не использовать схемы? Каждый арендатор изолирован в своей собственной схеме. Это также хорошо разделит наборы данных.
5 голосов
/ 16 ноября 2009

Первое, что приходит на ум, это то, что поиск animals > zoos > tenants медленнее, чем просто animals > tenants. И, скорее всего, это поиск, который вы будете делать часто (например, «получить всех животных для определенного арендатора, независимо от зоопарка»).

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

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

0 голосов
/ 12 ноября 2010

Причина N1 для безопасности.

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

Предположим, вы даете пользователю возможность изменять Животное. Вы создаете форму с выбором, который показывает зоопарк для текущего арендатора. Что произойдет, если пользователь взломает форму и передаст идентификационный номер другого арендатора?

Животное будет перемещено в другой зоопарк другого арендатора !!

Это настоящая боль в мультитенантном приложении!

0 голосов
/ 16 ноября 2009

Ну, у Боба может быть жираф в зоопарке № 1, а у Джо - лев в том же зоопарке. Они не должны смотреть на данные друг друга.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...