Необходимая информация о структуре базы данных

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

Propeller -> aircraft -> wood -> brand -> product. 

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

alt text http://img.ruphp.com/database-design/db_design.jpg

Теперь все это казалось прекрасным и денди, пока я не понял, что категория «древесина» также будет использоваться под гребным винтом -> airboat -> (дерево). Это означало бы, что «дерево» нужно будет воссоздавать каждый раз, когда я хочу использовать его под другим родителем. Это не конец света, но я хотел знать, есть ли более оптимальный способ этого.

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

*Редактировать. Подумал только о создании таблицы «тегов». Поэтому я мог бы назначить тег «дерево» или «металл» или «50inch» на 1 для многих предметов. Я бы по-прежнему сохранил тип родительского типа для основных категорий, но таким образом, категории не должны были идти настолько глубоко и не было бы повторения.

Во-первых, пользовательский интерфейс: как пользователь, я ненавижу искать продукт в каталоге, организованном строго иерархическим образом. Я никогда не помню, в какой суб-суб-sub-sub … категории есть «экзотический» продукт, и это заставляет меня тратить время на изучение «перспективных» категорий, чтобы обнаружить, что оно классифицировано в (для меня, по крайней мере ) странный путь.

То, что предлагает Кевин Пено, является хорошим советом и известно как граненый просмотр . Как пишет Marcia Bates в After Dot-Bomb: «Надеемся, что на этот раз правильно получить информацию о веб-информации » . Граничная классификация относится к иерархической классификации, поскольку реляционные базы данных относятся к иерархическим базам данных … ».

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

Чтобы быстро понять, что такое грандиозный поиск, есть некоторые демонстрации для изучения в проекте интерфейса поиска Flamenco – интерфейсы поиска, которые Flow .

Во-вторых, логика приложения: то, что предлагает Манитра, также является хорошим советом (как я понимаю), т.е. разделяя nodes и links дерева / графа в разных отношениях. Однако он называет «таблицу предков» (которая является гораздо более понятным интуитивным именем) называется транзитивным замыканием направленного ациклического графа (DAG) (отношение достижимости). Помимо производительности, он значительно упрощает запросы, как сказал Манитра.

Но я предлагаю представление для такой «таблицы предков» (транзитивное закрытие), так что обновления в режиме реального времени и инкрементальные, а не периодические с помощью пакетного задания. Существует код SQL (но я думаю, что его нужно немного адаптировать к конкретным СУБД) в документах, которые я упомянул в своем ответе на язык запросов для наборов графиков: вопрос моделирования данных . В частности, посмотрите на сохранение транзитивного закрытия графиков в SQL (.ps – postscript).

Связанные продукты-Категории

Первой точкой Манитры является также акцент.

Он говорит, что между продуктами и категориями существует отношение «многие ко многим». Т.е.: каждый продукт может быть в одной или нескольких категориях, и в каждой категории может быть ноль или более продуктов.

Приведенные отношения переменных (relvars) Продукты и категории такие отношения могут быть представлены, например, как ПК-рекурр с хотя бы атрибутами P # и C #, то есть номерами продуктов и категорий (идентификаторы) во внешних отношениях с соответствующими продуктами и категориями номера.

Это дополняет управление иерархиями категорий. Конечно, это всего лишь эскиз дизайна.

На гранжевом просмотре в SQL

Полезной концепцией реализации «граненного просмотра» является реляционное деление или, даже, реляционные сравнения (см. Нижнюю часть связанной страницы). Т.е. разделение PC (Products-Categories) на (растущий) список категорий, выбранных пользователем (фасетная навигация), получает только продукты в таких категориях (разумеется, категории предполагаются не всеми взаимоисключающими, в противном случае выбираются две категории, которые будут получены нулевые продукты).

СУБД на базе SQL обычно не хватает этих операторов (разделение и сравнение), поэтому я даю ниже некоторые интересные документы, которые реализуют / обсуждают их:

  • О СОЗДАНИИ ОТНОШЕНИЯ ОТНОШЕНИЙ ОТНОШЕНИЙ ОТНОСИТЕЛЬНО ОТНОШЕНИЙ (.pdf от Индекса сессий FIE 2003 );
  • Более простой (и лучший) подход SQL к реляционному разделению (.pdf из журнала «Образование информационных систем» – Содержание Том 13, № 2 (2002) );
  • Обработка запросов на поиск частых наборов элементов с помощью деления и набора операторов объединения с привязкой ;
  • Законы для переписывания запросов, содержащих операторов отделов ;
  • Алгоритмы и приложения для универсальной квантификации в реляционных базах данных ;
  • Оптимизация запросов с универсальной квантификацией в объектно-ориентированных и объектно-реляционных базах данных ;
  • (Требуется доступ ACM) О сложности деления и набора объединений в реляционной алгебре ;
  • (Требуется доступ к ACM) Быстрые алгоритмы для универсальной количественной оценки в больших базах данных ;

и так далее…

Я не буду вдаваться в подробности здесь, но взаимодействие между иерархиями категорий и просмотром фасетов требует особого внимания.

Отклонение от "плоскостности"

Я кратко рассмотрел статью, связанную с Pras , « Управление иерархическими данными в MySQL» , но я перестал читать после этих нескольких строк во введении:

Введение

Большинство пользователей в тот или иной момент имеют дело с иерархическими данными в базе данных SQL и, несомненно, узнали, что управление иерархическими данными не является целью реляционной базы данных. Таблицы реляционной базы данных не являются иерархическими (например, XML), а представляют собой просто плоский список . Иерархические данные имеют отношения родитель-потомок, которые не представлены естественным образом в таблице реляционных баз данных. …

Чтобы понять, почему эта настойчивость в плоскостности отношений является просто абсурдной , представьте себе куб в трехмерной картезианской системе координат : он будет идентифицирован по 8 координатам (триплетам), например P1 (x1, y1, z1), P2 (x2, y2 , z2), …, P8 (x8, y8, z8) [здесь нас не интересуют ограничения на эти координаты, так что они действительно представляют собой куб].

Теперь мы поместим этот набор координат (точек) в переменную отношения и назовем эту переменную Points . Мы будем представлять значение отношения Points как таблицу ниже:

 Очки |  x |  y |  z |
 ======= + ==== + ==== + ==== +
        |  x1 |  y1 |  z1 |
        + ---- + ---- + ---- +
        |  x2 |  y2 |  z2 |
        + ---- + ---- + ---- +
        |  .. |  .. |  .. |
        |  .. |  .. |  .. |
        + ---- + ---- + ---- +
        |  x8 |  y8 |  z8 |
        + ---- + ---- + ---- +

Этот куб «сплющивается» простым актом представления его в виде таблиц? Является ли отношение (значение) тем же, что и его табличное представление?

Переменная отношения принимает в качестве значений множество точек в n-мерном дискретном пространстве, где n – число атрибутов отношения («столбцы»). Что означает, что для n-мерного дискретного пространства должно быть «плоским»? Просто абсурд, как я писал выше.

Не поймите меня неправильно. Разумеется, SQL – плохо разработанный язык и что SQL-базирующиеся СУБД полны особенностей и недостатков (NULL, избыточность и т. Д.), Особенно плохих, DBMS-as- dumb-store type (никаких ссылочных ограничений, ограничений целостности, …). Но это не имеет ничего общего с реляционными данными, фантазированными ограничениями, наоборот: больше они отворачиваются от него, а хуже – результат.

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

В разделе «Вложенная модель набора»

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


EDIT: Стефан Эггермонт возразил в комментариях ниже: « Плоская модель списка – это проблема. Это абстракция реализации, которая затрудняет достижение производительности … ».

Теперь я хочу сказать, что:

  1. эта «модель с плоскими списками» – это фантазия : только потому, что одно изложение (представляет) отношения как таблицы («плоские списки») не означает, что отношения являются «плоскими списками» («объект» и его представления – это не одно и то же );
  2. логическое представление (отношение) и физические данные хранения (горизонтальные или вертикальные разложения, сжатие, индексы (хэши, b + дерево, r-дерево, …), кластеризация, разбиение на разделы и т. д.) различны; одна из точек реляционной модели данных ( RDM ) – отделить логику от «физической» модели (с преимуществами как для пользователей, так и для разработчиков СУБД);
  3. производительность является прямым следствием физических данных хранения (реализации), а не логического представления (комментарий Эггермонта – классический пример логико-физической путаницы ).

Модель RDM не ограничивает реализацию каким-либо образом; один может свободно вводить кортежи и отношения, как можно видеть. Отношения не обязательно являются файлами, и кортежи не обязательно являются записями файла. Такое соответствие является немой реализацией прямого изображения .

К сожалению, реализация СУБД на основе SQL слишком часто является немой реализацией прямого образа, и они страдают низкой производительностью в самых разных сценариях – существуют продукты OLAP / ETL для покрытия этих недостатков.

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

  • Vertica , которая является коммерческим преемником ..
  • C-Store: колонка-ориентированная СУБД ;
  • MonetDB ;
  • LucidDB ;
  • Kdb в пути;
  • так далее …

Конечно, дело не в том, что должен существовать «оптимальный» физический дизайн хранилища, но что любой дизайн физической памяти может быть абстрагирован красивым декларативным языком, основанным на реляционной алгебре / исчислениях (и SQL – плохой пример) или более непосредственно на логическом языке программирования (например, Prolog, см. мой ответ на вопрос « Пролог к ​​конвертеру SQL »). Хорошей СУБД должно быть изменение дизайна физической памяти «на лету» на основе статистики доступа к данным (и / или подсказок пользователя).

Наконец, в комментарии Эггермонта утверждение « Реляционная модель сжимается между облаком и превалистом » – это еще одна глупость, но я не могу дать опровержения здесь, этот комментарий уже слишком длинный.

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

Подводя итог, использование простой parent_category_id не очень хорошо масштабируется, и вам будет сложно записывать исполняемые SQL-запросы. Ответ заключается в использовании вложенных наборов, которые заставляют вас визуализировать вашу модель категории «многие ко многим» как наборы, вложенные внутри других наборов.

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

Однако я сомневаюсь, что это то, что вы хотите. Если я смотрю в категории Aircraft> Wood, то я бы не хотел видеть предметы из Boating> Wood . Есть две категории Wood, потому что они содержат разные предметы.

Мои предложения

  • поместите отношение «многие ко многим» между Item и Category, чтобы продукт мог отображаться во многих узлах иерархии (используется в ebay, sourceforge …)
  • сохранить иерархию категорий

Производительность по иерархии категорий

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

  • ChildId (идентификатор категории)
  • AncestorId (идентификатор родителя, родителя … всех категорий предков)

Это означает, что если у вас есть 3 категории: 1-Propeller> 2-plane> 3-wood

Затем таблица Ancestor будет содержать:

 ChildId AncestorId 1 2 1 3 2 3 

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

Благодаря этой таблице вам потребуется всего 1 соединение для запроса к категории (с ее дочерними элементами).

Если вам нужна помощь в создании таблицы Ancestor, просто дайте мне знать.

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

Подводя итог, использование простой parent_category_id не очень хорошо масштабируется, и вам будет сложно записывать исполняемые SQL-запросы. Ответ заключается в использовании вложенных наборов, которые заставляют вас визуализировать вашу модель категории «многие ко многим» как наборы, вложенные внутри других наборов.

Стоит отметить, что идея «нескольких категорий» в основном заключается в том, как работает «tagging». За исключением того, что в разделе «tagging» мы позволяем любому продукту иметь много категорий. Позволяя любому продукту быть во многих категориях, вы позволяете клиенту полностью фильтровать свой поиск, начиная с того места, где, по их мнению, им нужно начинать . Он мог бы нажимать на «самолеты», затем «дерево», затем «турбореактивный двигатель» (или что-то еще). Или они могут начать поиск с Вуда и получить тот же результат.

Это даст вам максимальную гибкость, и клиент получит лучший UX , но все же позволит вам поддерживать иерархическую структуру. Итак, в то время как цитируемый ответ предлагает разрешить категории M: N категориям, мое предложение состоит в том, чтобы позволить продуктам иметь категории M: N.

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

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

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

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

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

Аналогичным образом вы можете использовать префиксы тегов, такие как: style: wood mfg: Nike, позволяющий выполнять относительно сложную категоризацию и развёртывание без трудностей сложной перестановки базы данных или кошмаров EAV, все в системе тегов, которая дает вам больше возможностей для размещения ожидания пользователей. Помните, что пользователи могут рассчитывать на перемещение продуктов различными способами, чем вы, как база данных, и бизнес-владелец может ожидать. Использование системы тегов может помочь вам включить интерфейс для покупок без ущерба для вашего инвентаря или отслеживания продаж или чего-либо еще.

Теперь все это казалось прекрасным и денди, пока я не понял, что категория «древесина» также будет использоваться под гребным винтом -> airboat -> (дерево). Это означало бы, что «дерево» нужно будет воссоздавать каждый раз, когда я хочу использовать его под другим родителем. Это не конец света, но я хотел знать, есть ли более оптимальный способ этого.

Что, если у вас есть самолет, который является деревянной конструкцией, но пропеллером может быть углеродное волокно, стекловолокно, металл, графит?

Я бы определил таблицу материалов и использовал ссылку на внешний ключ в таблице элементов. Если вы хотите поддерживать более одного материала (IE: скажем, есть металлическая переинформация или винты …), вам понадобится таблица corrollary / lookup / xref.

Таблица MATERIALS_TYPE_CODE

  • MATERIALS_TYPE_CODE pk
  • MATERIALS_TYPE_CODE_DESC

Таблица PRODUCTS

  • PRODUCT_ID , pk
  • MATERIALS_TYPE_CODE fk Если только один материал когда-либо ассоциируется

Таблица PRODUCT_MATERIALS_XREF

  • PRODUCT_ID , pk
  • MATERIALS_TYPE_CODE pk

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

Таблица KITTED_PRODUCTS

  • PARENT_PRODUCT_ID , fk
  • CHILD_PRODUCT_ID , fk

… и он поддерживает иерархическое отношение, потому что ребенок может быть родителем чего-то другого.

Вы можете легко протестировать свои проекты БД на http://cakeapp.com