Вопрос проектирования базы данных - PullRequest
8 голосов
/ 05 апреля 2009

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

В моей базе данных есть таблица [User] с базовыми данными, которые вы ожидаете, такими как имя пользователя, пароль и т. Д. *

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

Я испытываю желание добавить таблицу UserProperties со столбцами UserID, PropertyKey и PropertyValue. Такой подход хорошо согласуется с требованиями.

Меня беспокоит то, что если у каждого пользователя, скажем, 100 свойств, когда в базе данных миллион пользователей, у нас будет 100 000 000 строк свойств.

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

Есть идеи или мысли по поводу производительности? Идеи для лучшего дизайна БД?

Спасибо!

UPDATE:

Во-первых, большое спасибо за все отличные ответы!

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

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

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

Ответы [ 10 ]

11 голосов
/ 05 апреля 2009

То, что вы описываете, - это база данных Entity-Attribute-Value, которая часто используется именно для той ситуации, которую вы описываете, разреженных данных, связанных с одной сущностью.

Таблица E-A-V проста для поиска. Проблема не в поиске строк, а в поиске связанных строк.

Наличие разных таблиц для разных сущностей обеспечивает моделирование предметной области, но они также предоставляют слабую форму метаданных. В E-A-V нет таких абстракций. (Аналогия Java с E-A-V будет означать, что формальные аргументы всех функций имеют тип Object - так что вы не будете проверять тип.)

Мы можем легко найти ключи свойств, но ничто не группирует эти ключи свойств.

В Википедии есть очень хорошая статья об E-A-V, но прочитайте ее сейчас - в основном это работа одного автора, и она намечена для «улучшения».

7 голосов
/ 05 апреля 2009

Я рекомендую вам рассмотреть подход, известный как вертикальное разбиение. Это означает, что вы продолжаете определять таблицы с помощью ключа UserID, вы можете называть их User1, User2 и т. Д. Начать новую таблицу, когда вы достигнете максимального размера строки для вашей базы данных. Преимущество этого подхода заключается в том, что значения по-прежнему являются истинными атрибутами базы данных. Это сэкономит время при работе с этими данными, например, привязка данных.

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

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

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

3 голосов
/ 05 апреля 2009

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

1 голос
/ 05 апреля 2009

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

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

Мой совет: постарайтесь собрать все это в одну таблицу, а затем запустите ее с некоторыми данными испытаний. ЕСЛИ это не сработает, тогда вы могли бы пойти по пути решения с несколькими таблицами или даже решения без БД (в конце концов, это не серебряные пули).

1 голос
/ 05 апреля 2009

с учетом заявленных ограничений, я не думаю, что у вас действительно есть другой выбор!

хорошо, вы можете разделить пользовательские атрибуты по нескольким таблицам, использующим один и тот же UserId в качестве их первичного ключа (и кластеризованного индекса), но это может или не может улучшить производительность

если вы говорите только о 100 атрибутах, это может быть обработано одной таблицей (в MS-SQL макс. 1023 неключевых столбцов); если атрибуты заполнены редко, таблица пользовательских атрибутов потенциально может быть более компактной (точно знает только ваш профилировщик)

1 голос
/ 05 апреля 2009

Несколько вариантов, которые я могу придумать:

  • битовые поля: вы можете хранить там много значений и добавлять дополнительные поля по мере необходимости или даже использовать отдельную таблицу
  • помещает наиболее распространенные настройки в пользовательскую таблицу, а настройки, которые могут отсутствовать у каждого пользователя во второй таблице
  • хранит только те настройки, которые отличаются от настроек по умолчанию
1 голос
/ 05 апреля 2009

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

1 голос
/ 05 апреля 2009

Мы реализовали стратегию UserProperties в нескольких проектах. Это обычная модель, и с соответствующими индексами у нас никогда не возникало проблем с производительностью.

Еще одним преимуществом является то, что вы можете иметь две или более таблицы свойств, если это необходимо для управления доступом пользователей. Например, общие свойства могут быть в таблице PublicUserProps, в то время как конфиденциальная информация (я не знаю, что вы храните, но ssn, информация о заработной плате и т. Д.) Может быть в таблице ControlledUserProps, в которую только некоторые пользователи могли бы читать или редактировать прав.

1 голос
/ 05 апреля 2009

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

Группировка может иметь отношение один к одному или один ко многим с пользователем ...

1 голос
/ 05 апреля 2009

Я сомневаюсь, что в таблице Users будет так много значений данных 1-к-1, что вам не хватит места в строке. Вы должны только выгружать значения 1-ко-многим в другую таблицу, используя идентификатор пользователя в качестве внешнего ключа. Я считаю маловероятным, что вашей пользовательской таблице потребуется так много полей VARCHAR (), которые нельзя каким-либо образом превратить в FK из основной таблицы значений. Какие пользовательские атрибуты вы поддерживаете?

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