Ссылки на таблицы SQL ... лучше иметь таблицу ссылок или столбец с разделителями? - PullRequest
4 голосов
/ 21 января 2010

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

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

Второй метод заключается в добавлении столбца в таблицу пользователей, в которой хранится список ролей с разделителями. Это устранит необходимость в третьей таблице связывания, которая может оказать положительное влияние на рост базы данных. Недостатком является то, что в SQL нет возможности использовать списки с разделителями. Единственный способ обработки этой информации, который я нашел, - это использование временной таблицы и пользовательской функции.

При просмотре моих планов выполнения, событие "сканирование таблицы" - это то, которое занимает больше всего ресурсов. Имеет смысл, что исключение таблицы из уравнения ускорит процесс. Функция занимает менее 1% ресурсов.

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

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

Пожалуйста, скажите мне, какой метод вы предпочитаете (даже если он отличается от моих двух) и почему.

Спасибо.

Ответы [ 6 ]

10 голосов
/ 21 января 2010

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

Отдельная таблица (нормализованная, отношение многие ко многим) - это путь, и при правильном индексировании у вас не будет полного сканирования.

Например:

User:  UserId, Name, ....
Role:  RoleId, Name, ....
UserRole:  UserRoleId, UserId, RoleId

(UserRoleId необязателен, в качестве альтернативы можно указать, что PK будет UserId + RoleId, я не буду здесь обсуждать суррогатные и составные ключи)

Вам нужно, чтобы индекс (UserId, RoleId) был УНИКАЛЬНЫМ, чтобы не создавать дубликатов. Это также поможет с любыми запросами, когда вы пытаетесь определить, играет ли конкретный пользователь определенную роль (ГДЕ userId = x И roleId = y)

Если вы просматриваете все роли, которые есть у пользователя, вам нужен индекс только для UserId.

И наоборот, если вы ищите всех пользователей данной роли, индекс только для roleId ускорит это. Если вы не выполняете этот запрос или делаете это очень редко, то отсутствие этого индекса немного увеличит производительность для вставки / обновления, так как это на одну вещь меньше. Это тщательный баланс, который настраивает базу данных.

8 голосов
/ 21 января 2010
  1. Сканирование таблицы означает, что у вас нет индексов или ваш запрос не позволяет их использовать. В базе данных безопасности вам редко нужно загружать весь список пользователей / ролей, за исключением случаев, когда это приложение для администратора. Вы должны решить эту проблему в своем дизайне.

  2. Списки с разделителями нарушают первую нормальную форму (1NF), а почти всегда вызывают проблемы в долгосрочной перспективе. Что произойдет, если вы хотите получить всех пользователей с определенной ролью? Как вы пишете этот запрос? Не ходи по этой дороге. Нормализовать это.

  3. Если вы используете правильные типы столбцов (т. Е. Не varchar(4000) или varchar(max) везде), дисковое пространство действительно не должно быть проблемой. Да, он будет расти "в геометрической прогрессии" - и что? Базы данных хороши при таком масштабировании. Если вы не пытаетесь запустить это на жестком диске 10 Гб, беспокоиться не о чем. И если вы пытаетесь запустить его на жестком диске 10 ГБ, у вас, вероятно, возникнут большие проблемы.

Краткий ответ: не используйте список с разделителями. Нормализация.

6 голосов
/ 21 января 2010

Первый вариант. Это называется соединительным столом «многие ко многим». Это будет хорошо работать, если вы создадите соответствующие индексы.

Не используйте второй «денормализованный» вариант.

4 голосов
/ 21 января 2010

Вы можете использовать отдельный стол или вернуться к пещерным людям с долотами. Выбор за вами.

2 голосов
/ 21 января 2010

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

0 голосов
/ 12 января 2017

Хотя я очень рекомендую нормализованный метод, который предлагают все. Я верю, что наличие системы ролей на основе перечисления позволит вам иметь одну цифру для столбца «роли» и позволит вам избежать создания другой таблицы.

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