Нужна подсказка по простому дизайну БД MySQL
Я пытаюсь создать простую базу данных предметов, используя MySQL для игры. Вот как будут выглядеть мои 3 таблицы
Предметы itemId | имя элемента ------------------- 0001 | часть груди 0002 | меч 0003 | шлем
attribute (таблица поиска атрибутов) attributeId | attributeName --------------------------------- 01 | сила 02 | ловкость 03 | интеллект 04 | защита 05 | повреждение 06 | мана 07 | выносливость 08 | описание 09 | тип
item_attributes (таблица соединений) itemId | attributeId | значение (смешанный тип, плохо?) ------------------------------------ 0001 | 01 | 35 0001 | 03 | 14 0001 | 09 | броня 0001 | 08 | созданный удивительными эльфами 0002 | 09 | оружие 0002 | 05 | 200 0002 | 02 | 15 0002 | 08 | ваш средний меч 0003 | 04 | 9000 0003 | 09 | броня 0003 | 06 | 250
Моя проблема с этим дизайном заключается в том, что value
колонка в item_attributes
стол должен использовать varchar
тип данных, так как данные значения могут быть int
, char
, varchar
, Я думаю, что это плохой подход, потому что я не смог бы быстро сортировать свои предметы по определенным атрибутам. Это также приведет к снижению производительности при обработке запроса, например, получить элементы с силой атрибута, значение которой находится в диапазоне от 15 до 35.
Вот мое потенциальное решение. Я просто добавил data_type
столбец к attributes
Таблица. Так это будет выглядеть примерно так
атрибуты (таблица поиска атрибутов) attributeId | attributeName | тип данных -------------------------------------------------- - 01 | сила | ИНТ 09 | тип | голец 08 | интеллект | VARCHAR
Тогда я бы добавил еще 3 столбца item_attributes
Таблица, int
, char
, varchar
, Вот как новый item_attributes
стол будет выглядеть так.
item_attributes (таблица соединений) itemId | attributeId | значение | Int | символ | VARCHAR -------------------------------------------------- ---------------------- 0002 | 09 | оружие | ноль | оружие | ноль 0002 | 05 | 200 | 200 | ноль | ноль 0002 | 02 | 15 | 15 | ноль | ноль 0002 | 08 | ваш средний меч | ноль | ноль | ваш средний меч
Так что теперь, если бы я был сортировать элементы на основе его strength
атрибут, я бы использовал int
колонка. Или искать элемент на основе его описания, я бы поискал varchar
колонка.
Однако я все еще считаю, что мой дизайн немного странный. Теперь я должен был бы посмотреть data_type
колонка в attribute
таблица и динамически определить, какой столбец в item_attributes
Таблица имеет отношение к тому, что я ищу.
Любые материалы будут с благодарностью.
Заранее спасибо.
РЕДАКТИРОВАТЬ 29.11.2010 Вот подробный список моих товаров
-------------------------------------- http://wow.allakhazam.com/ihtml?27718 Ножные латы защитника Алдора Персональный при поднятии LegsPlate Броня 802 +21 к силе +14 к ловкости +21 к выносливости Уровень предмета 99 Если на персонаже: рейтинг меткости +14. -------------------------------------- http://wow.allakhazam.com/ihtml?17967 Изысканная чешуя ониксии Натуральная кожа Уровень предмета 60 -------------------------------------- http://wow.allakhazam.com/ihtml?27719 Алдорские леггинсы счастья Персональный при поднятии LegsLeather Броня 202 +15 к ловкости +21 к выносливости Уровень предмета 99 Если на персонаже: сила атаки +28. Если на персонаже: рейтинг меткости +20. -------------------------------------- http://wow.allakhazam.com/ihtml?5005 Emberspark Pendant Становится персональным при надевании NeckMiscellaneous +2 к выносливости +7 Дух Требуется уровень 30 Уровень предмета 35 -------------------------------------- http://wow.allakhazam.com/ihtml?23234 Синий Брианит Ловкости Драгоценные камни Требуется уровень 2 Уровень предмета 10 +8 к ловкости -------------------------------------- http://wow.allakhazam.com/ihtml?32972 Пивные очки Персональный при поднятии уникальный HeadMiscellaneous Уровень предмета 10 Если на персонаже: Гарантировано Belbi Quikswitch, чтобы КАЖДЫЙ выглядел привлекательно! -------------------------------------- http://wow.allakhazam.com/ihtml?41118 Gadgetzan Present Персональный при поднятии уникальный Уровень предмета 5 "Пожалуйста, вернитесь к организатору сезона" -------------------------------------- http://wow.allakhazam.com/ihtml?6649 Обжигающий тотемный свиток уникальный Квестовый предмет Требуется уровень 10 Уровень предмета 10 Использование: -------------------------------------- http://wow.allakhazam.com/ihtml?6648 Тотем свитка каменной кожи уникальный Квестовый предмет Требуется уровень 4 Уровень предмета 4 Использование: -------------------------------------- http://wow.allakhazam.com/ihtml?27864 Brian's Bryanite расширенного копирования стоимости Драгоценные камни Уровень предмета 10 чары для драгоценного камня --------------------------------------
РЕДАКТИРОВАТЬ № 2
- Эти 10 примеров не являются репрезентативными для всех 35316 данных, которые я собрал.
- "Разное" означает, что предмет относится к обеим категориям: "шея" и "разное".
- Уникальный означает, что только один предмет может быть использован для персонажа.
- Не читайте слишком много в "Действие", это просто описание квеста
- Когда предмет говорит: "Надеть: увеличить силу атаки на 28", это просто означает +28 к силе атаки персонажа игрока. Это +15 к ловкости.
Модельная диаграмма
Вот пример того, как выглядит запрос
Выбрать * от itemattributestat где item_itemId=251 item_itemId | attribute_attributeId | значение | listOrder ======================================================= "251", "9", "0", "1" "251", "558", "0", "2" "251", "569", "0", "3" "251", "4", "802", "4" "251", "583", "21", "5" "251", "1", "14", "6" "251", "582", "21", "7" "251", "556", "99", "8" "251", "227", "14", "9"
Порядок списка здесь, чтобы отслеживать, какой атрибут должен быть указан первым. Для форматирования
создать представление itemDetail as выберите Item_itemId в качестве идентификатора, i.name в качестве элемента, a.name в качестве атрибута, значение from ((itemattributestat присоединяет элемент как i к Item_itemId=i.itemId) Атрибут объединения как атрибут Attribute_attributeId=a.attributeId) упорядочить по Item_itemId asc, listOrder asc;
Приведенный выше вид производит следующее с
Выбрать * из предмета детали где id=251; id | элемент | атрибут | значение '251', 'Ножные латы Алдора Защитника', 'Персональный при поднятии', '0' "251", "Ножные латы Алдора Защитника", "Ноги", "0" "251", "Ножные латы Алдора Защитника", "Тарелка", "0" '251', 'Ножные латы Алдора Защитника', 'Броня', '802' "251", "Ножные латы Алдора Защитника", "Сила", "21" "251", "Ножные латы Алдора Защитника", "Ловкость", "14" "251", "Ножные латы Алдора Защитника", "Выносливость", "21" '251', 'Ножные латы Алдора Защитника', 'Уровень предмета', '99' "251", "Ножные латы Алдора Защитника", "Если на персонаже: Повышает рейтинг меткости на @@.", "14"
Атрибут со значением 0 означает, что имя атрибута представляет тип элемента. 'Equip: Improves hit rating by @@.', '14'
@@ здесь заполнитель, обработанный вывод в браузере будет 'Equip: Improves hit rating by 14.'
3 ответа
Почему у вас есть attribute
стол?
Атрибуты - это столбцы, а не таблицы.
Ссылка на сайт ничего не говорит нам.
Основная идея базы данных заключается в том, что вы объединяете множество небольших таблиц, при необходимости, для каждого запроса, поэтому вам нужно к этому привыкнуть. Конечно, это дает вам сетку, но короткую и сладкую, без нулей. То, что вы пытаетесь сделать, это избегать таблиц; идти только с одной массивной сеткой, которая полна нулей.
(надрез)
Не добавляйте префиксы к именам ваших атрибутов (имен столбцов). Это станет ясно вам, когда вы начнете писать SQL, который использует более одной таблицы: тогда вы можете использовать имя таблицы или псевдоним для добавления префиксов к любым именам столбцов.
Исключением является PK, который отображается полностью и используется в этой форме, где бы он ни был FK.
Просмотрите сайт и прочитайте несколько вопросов по SQL.
После этого вы можете подумать, хотите ли вы strength
а также defense
быть атрибутами (столбцами) type
; или нет. И так далее.
Ответы на комментарии 30 ноября 10
,
Отлично, вы понимаете свои данные. Правильно. Теперь я понимаю, почему у вас была таблица атрибутов.
Пожалуйста, убедитесь, что эти 10 примеров являются репрезентативными, я внимательно на них смотрю.
- Тип: Драгоценный камень Имя:Emberspark Pendant ... Или это шейка Разное?
- Является ли Unique истинным ItemType? Думаю, нет
- Action.Display "Пожалуйста, вернитесь к организатору сезона"
- Где находятся Атрибуты для
AttackPower
а такжеHitRating
?
,
Сколько существует различных типов товаров (из 35000), например, мой Кластер продуктов. Другой способ сформулировать этот вопрос - сколько существует вариантов. Я имею в виду, по сути, а не 3500 предметов ÷ 8 атрибутов?
Изменится ли item_attributes без выпуска программного обеспечения (например, нового
Inner Strength
атрибут)?По элементу, какие атрибуты повторяются (более одного); пока вижу только экшн?
Это игра, поэтому вам нужен жесткий и очень быстрый БД, может быть, полностью сохраняющий память, верно. Нет нуля. Нет VAR ничего. Кратчайшие типы данных. Никогда ничего не дублируйте (не повторяйте себя). Вы довольны битами (логическими значениями) и векторами?
Нужно ли вам легко переводить эти регулярные выражения в SQL, или вы довольны серьезным слогом для каждого (т. Е. Как только вы заставите их работать в SQL, они довольно стабильны, и тогда вы не будете возиться с этим, если только не найдете ошибку) (без сарказма, серьезный вопрос)?
6.1 Или, может быть, все наоборот: база данных находится на диске; вы загружаете его в память один раз; вы запускаете регулярные выражения для этого во время игры; изредка записываю на диск. Поэтому нет необходимости переводить регулярные выражения в SQL?
Вот модель данных о том, куда я направляюсь, это не совсем точно; это будет модулироваться вашими ответами. Чтобы было ясно:
Шестая нормальная форма - строка состоит из первичного ключа и, самое большее, одного атрибута.
Я нарисовал (6.1), а не (6), потому что ваши данные подтверждают мое убеждение, что вам нужна чистая 6NF реляционная база данных
Моя модель данных кластера продуктов, пример лучше, чем EAV, имеет значение 6NF, затем снова нормализуется (не в смысле нормальной формы) с помощью DataType, чтобы уменьшить число таблиц, которые вы уже видели. (EAV люди обычно идут за один или несколько гигантских столов.)
Это прямой 5NF, только в 6NF только 2 таблицы справа.
Ссылка на нотацию IDEF1X для тех, кто не знаком со стандартом реляционного моделирования.
Ответ на Edit #2 05 декабря 10
1.1. Хорошо, исправлено.
1.2. Тогда Is Unique является индикатором (логическим) для Item.
1.3. Действие. Я понимаю. Так где вы собираетесь хранить его?
1.4. NeckMiscellaneous означает, что товар находится в обеих категориях Neck
а также Misc
, Это означает, что два отдельных Item.Name=Emberspark Pendant
каждый с другой категорией.
,
2. и 5. Так что вам нужен быстрый быстрый резидентный дБ. Вот почему я пытаюсь перевести вас через линию, от GridLand, в RelationalLand.
,
3. Хорошо, мы остаемся с пятой нормальной формой, нет необходимости в 6NF или кластере продуктов (таблицы на тип данных). Софар Values
все целые числа.
,
4. Я могу видеть дополнительно: Level
, RequiredLevel
, IsUnique
, BindsPickedUp
, BindsEquipped
,
,
5. Биты логические { 0 | 1 } Векторы необходимы для (реляционных) проекций. Мы доберемся до них позже.
,
6. Хорошо, вы объяснили, что вы не переводите регулярные выражения в SQL. (Слог означает тяжелый труд).,
7. Что такое Category.ParentId? Родительская категория? Это не подходило раньше.
,
8. Attribute.GeneratedId?
Пожалуйста, оцените модель данных (обновлено). У меня есть еще несколько столбцов, в дополнение к тому, что есть у вас. Если есть что-то, чего вы не понимаете в модели данных, задайте конкретный вопрос. Вы прочитали документ с обозначениями, верно?
я имею Action
как таблица, с ItemAction
держа Value
: Equip: increase attack power by 28
является Action.Name
знак равно Increase attack power by
а также ItemAction.Value
=28.
Я думаю, что имея data_type
Колонка еще больше усложняет конструкцию. Почему бы просто не иметь type
а также description
быть колоннами на items
Таблица? Само собой разумеется, что каждый элемент будет иметь каждое из этих значений, а если нет, то null
будет хорошо в текстовом столбце.
Вы можете еще больше нормализовать type
имея item_types
стол и type
колонка в items
будет числовой внешний ключ к этой таблице. Может быть необязательным, но может облегчить выбор типа на items
Таблица.
Изменить: Думая об этом дальше, кажется, что вы, возможно, пытаетесь, чтобы ваши таблицы данных соответствовали модели предметной области. Ваши предметы будут иметь ряд атрибутов в логике приложения. Это отлично. Имейте в виду, что логика вашего приложения и схема сохранения базы данных могут отличаться. На самом деле, они не должны полагаться друг на друга на уровне дизайна. Во многих небольших приложениях они, вероятно, будут одинаковыми. Но есть и исключения. Код (предположительно объектно-ориентированный, но не обязательно) и реляционные данные имеют разный дизайн и разные ограничения. Разделение их друг с другом позволяет разработчику использовать преимущества их проектов, а не ограничиваться их ограничениями.
Вы имеете дело с двумя общими проблемами:
- Сущности, которые похожи друг на друга, но не идентичны (все предметы имеют имя и описание, но не обязательно интеллект).
- Конструкция, в которой вам нужно добавлять атрибуты, когда база данных находится в рабочем состоянии (вы можете довольно легко предсказать, что в какой-то момент вам нужно будет добавить, например, атрибут устойчивости к магии для некоторых предметов).
Вы решили свою проблему, заново изобрав систему EAV, в которой вы храните имена и значения атрибутов как данные. И вы заново обнаружили некоторые проблемы с этой системой (проверка типов, целостность отношений).
В этом случае я бы лично выбрал решение на полпути между реляционным и EAV. Я бы взял общие столбцы и добавил их в виде столбцов либо в таблицу элементов, либо, если элементы представляют виды элементов, а не отдельные элементы, в таблицу items_owners. Эти столбцы будут включать описание и, возможно, тип, а в приведенном вами примере они будут в значительной степени соответствовать текстовым столбцам. Затем я бы сохранил существующий макет для тех атрибутов, которые являются числовыми рейтингами, делая тип значения int. Это дает вам проверку типов и правильную нормализацию целочисленных атрибутов (вы не будете хранить много NULL) за счет случайного типа или описания NULL.