Многозначные атрибуты в реляционных базах данных? - PullRequest
1 голос
/ 22 сентября 2011

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

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

UserID          Attribute1

User1           a,b,c
User2           x,y,z
User3           a,x,y
User4           c,b,z
[a,b,c,x,y,z are to be strings]

Есть еще один пользователь User5, которому я должен дать несколько советов о других пользователях в зависимости от того, соответствует ли его Attribute1 кому-либо из других 4 пользователей.

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

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

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

UserID          Attribute1

User1           a
User1           b
User1           c
User2           x
User2           y
User2           z
User3           a
User3           x
User3           y
User4           c
User4           b
User4           z

Есть ли более быстрый способ решения таких ситуаций в базах данных?Или есть какие-то встроенные функции современных баз данных, которые можно использовать?

Ответы [ 3 ]

6 голосов
/ 22 сентября 2011

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

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

Наличие миллиона записей в таблицене проблема.У нас есть несколько таблиц, в которых более 100 миллионов записей.

3 голосов
/ 22 сентября 2011

Помимо того, что другие говорили о нормализации, я бы хотел ответить на часть " или использовать любую встроенную функцию современных баз данных для использования? " на ваш вопрос:

PostgreSQL имеет довольно изящное расширение под названием hstore, которое делает именно это и оптимизировано.

Тип данных hstore, по сути, является парой ключ / значение, в которой вы можете хранить что угодно.В вашем примере что-то вроде этого:

INSERT INTO user_attributes
(user_id, , attributes)
VALUES
(1, ('att1 => x, att2 => y'));

Вставит ключи att1 и att2 в атрибуты столбца.Это может быть проиндексировано для быстрого поиска.

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

SELECT *
FROM user_attributes
WHERE attributes @> ('att1 => "Some Value"')

Это вернет все строки, у которых есть ключ с именем att1 и где он сопоставлен со значением «Некоторое значение».Приведенный выше оператор будет использовать существующий индекс для столбца, поэтому поиск выполняется почти так же быстро, как и для «реального» столбца.Вышеуказанная инструкция занимает ~ 2 мс на моем ноутбуке, чтобы найти строку в таблице с 100 000 строк.

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

SELECT user_id,
       (attributes -> 'att1')
FROM user_attributes
WHERE attributes ? 'att1'

найдет все строки, в которых определен att1, и выведет их значение.

1 голос
/ 22 сентября 2011

Для таблицы nn вы можете нормализовать ее до 3-х таблиц (в транзакционной модели) users - user_attribute - атрибуты, где таблица user_attribute состоит из первичного ключа пользователей и атрибутов. Ключи обычно индексируются и, следовательно, довольно быстро читать ops

РЕДАКТИРОВАТЬ ПОСЛЕ ВОПРОСА

Users
int Id PrimaryKey
string name

User_Attribute
UserId PrimaryKey (FK to Users.Id)
AttributeId PrimaryKey (FK to Attributes.Id)

Attributes
int Id PrimaryKey
Value

это приведет к тому, что таблица будет содержать только пользователей, таблица будет содержать только атрибуты, а таблица будет содержать информацию о том, какой пользователь содержит что

например

   Users      User_Attribute      Attrubutes      
id  Name   UserId AttributeId  Id Value
1   User1  1      1            1  Att1
2   User2  1      2            2  Att2
           2      1            3  Att3  
           2      3
...