Схема базы данных для нескольких флажков

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

Например:

Известные языки: checkbox PHP, Java, Ruby

Знание ОС: Windows, Linux, Mac

В настоящее время мои таблицы базы данных выглядят так:

USER
----------------------------------------
|  ID  |  Name      |  
-----------------------
|   1  |    John    |    
-----------------------
|   2  |    Alice    |    
-----------------------

LANGUAGES
----------------------------------------
|  ID  | User_ID(FK)     | lang-name  | 
----------------------------------------
|   1  |    1            |   PHP      |
----------------------------------------
|   1  |    2            |   Java     |
----------------------------------------

OS
----------------------------------------
|  ID  | User_ID(FK)     | os-name  | 
----------------------------------------
|   1  |    1            | Windows  |
----------------------------------------
|   1  |    2            |  Windows |
----------------------------------------

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

Есть ли лучший способ организовать схему?


person Mark    schedule 22.05.2012    source источник
comment
Какую СУБД вы используете? Постгрес SQL? Оракул? ДБ2? Жар-птица? (Для PostgreSQL было бы очень простое и эффективное решение)   -  person a_horse_with_no_name    schedule 23.05.2012
comment
Я использую Sqlite прямо сейчас, но в будущем перейду на PostgreSQL.   -  person Mark    schedule 23.05.2012


Ответы (1)


Возможно, вы могли бы сделать Language и OS первоклассными объектами в базе данных с их собственными таблицами, а затем использовать таблицу соединения для связи "многие ко многим" с User. Что-то вроде этого:

User
---------
ID
Name
etc...

Language
---------
ID
Name

OS
---------
ID
Name

UserLanguage
---------
UserID
LanguageID

UserOS
---------
UserID
OSID

Таким образом, фактические объекты (User, Language, OS) являются самодостаточными и содержат только те данные, которые имеют для них значение, не загрязняют и не дублируют их отношения друг к другу. И отношения содержатся в своих собственных простых числовых таблицах, которые сами по себе не являются сущностями, а представляют собой просто связи «многие ко многим» между сущностями.

Никакие данные не дублируются (в вашем образце данных Language и OS будут иметь только по три записи, по крайней мере, на данный момент), и это будет намного удобнее для ORM и других фреймворков, если вам когда-нибудь понадобится их использовать.

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

User
---------
ID
Name
etc...

Lookup
---------
ID
LookupTypeID
Value

LookupType
---------
ID
Value

UserLookup
---------
UserID
LookupID

Это дает вам большую гибкость. В вашем образце данных Language и OS будут записями в LookupType. Все языки и операционные системы будут значениями в Lookup, которые ссылаются на соответствующие им LookupType. Так что до сих пор нет повторения данных. И таблица UserLookup является единственной таблицей ссылок «многие ко многим».

Но будьте осторожны с этим дизайном. Он гибкий, однозначно. Но когда вы используете эту табличную структуру в качестве реальных моделей предметной области, вы сталкиваетесь с ситуациями, когда такие термины, как «Поиск», становятся бизнес-терминами, и это, вероятно, не так. «Язык» и «ОС» — это фактические модели. Я бы рекомендовал использовать представления или, возможно, хранимые процедуры, чтобы абстрагировать эту структуру от кода. Таким образом, код будет извлекать языки из представления или процедуры Language, а не напрямую из таблицы Lookup.

person David    schedule 22.05.2012
comment
Спасибо за ответ. При дальнейших размышлениях я решил вместо этого сохранить все это в виде файла xml из-за огромного количества таблиц базы данных, которые мне пришлось бы создавать в противном случае. - person Mark; 23.05.2012
comment
@Tulasi: Я предполагаю, что под одним лишь числом вы имеете в виду, что будет много таблиц поиска, помимо Language и OS? Если вы говорите о десятках таблиц, это на самом деле не так плохо, как вы думаете, если количество сущностей достаточно статично. Если вы ожидаете, что они изменятся, то возможен более творческий подход к поиску данных. У вас может быть одна таблица Lookup и таблица LookupType. Добавление/удаление типов поиска становится простым в этой схеме. Вы по-прежнему можете предоставлять представления или хранимые процедуры для строго типизированных сущностей для типов поиска. - person David; 23.05.2012
comment
Да. Мне потребуется создать 20-30 таблиц с 4-5 записями в них. Используя таблицу Lookup и таблицу LookupType, мне больше не нужно, чтобы каждая из них имела таблицы соединения, но по-прежнему кажется, что много таблиц и много запросов, когда я хочу отобразить информацию о наборе навыков для одного пользователя. Я все еще немного смущен тем, какие варианты лучше - хранить в виде xml или использовать таблицы базы данных. Любая причина, по которой выбор xml плох? - person Mark; 23.05.2012
comment
@Tulasi: Ну, XML далеко не так оптимизирован, как реляционная база данных, это точно. Таким образом, производительность является одной из причин. Отчетность — это другой вопрос: как бы вы сообщили о содержимом больших двоичных объектов XML? Как бы вы обеспечили целостность данных? Я не понимаю, как в этом случае 3 таблицы для всех поисковых запросов будут большим количеством таблиц. Запросы были бы довольно стандартным шаблоном, и представления могут помочь с этим. Вам просто нужно выбрать из Lookup, где LookupType — известный идентификатор, или присоединиться к таблице LookupType в выборе, где LookupType.Value — известная строка. - person David; 23.05.2012