Вопрос

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

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

Я пытаюсь придумать надежную схему для размещения предоставленных мне данных, поскольку мне нужно будет загрузить их относительно скоро, а данные, которые они мне предоставили, похоже, не соответствуют типу данных, которые они мне предоставили. обеспечить демонстрацию на своем образце веб-сайта (http://www.iteminfo.com).В любом случае, я не собираюсь повторно использовать их структуру представления, так что это спорный вопрос, но я просматривал сайт, чтобы получить некоторые идеи о том, как структурировать вещи.

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

Я, вероятно, собираюсь создать витрину электронной коммерции, используя эти данные с помощью Ruby on Rails (или, во всяком случае, это мой план), поэтому я стараюсь избежать ошибок в дальнейшем или создания раздутого приложения - может быть, я я слишком много об этом думаю, но предпочитаю перестраховаться;наши предыдущие данные были настоящим беспорядком и стоили компании десятков тысяч долларов из-за упущенных продаж из-за противоречивых и неточных данных.Кроме того, я собираюсь немного отойти от соглашений Rails и убедиться, что моя база данных надежна и обеспечивает соблюдение ограничений (я планирую сделать это и на уровне приложения), так что мне тоже нужно это учитывать.

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

Это было полезно?

Решение

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

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

Другие советы

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

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

Компромиссом является небольшая дополнительная сложность БД (таблица замыканий и триггеры) при гораздо меньшей сложности пользовательского интерфейса и кода бизнес-уровня.

Если я правильно понимаю, вы хотите взять отдельные таблицы и превратить их в иерархию, которая будет храниться в одной таблице с самоссылающимся FK.

Как правило, это более гибкий подход (например, если вы хотите добавить пятый уровень), НО SQL и реляционные модели данных, как правило, не очень хорошо работают с такими связанными списками, даже с новым синтаксисом, таким как CTE серверов MS SQL.По общему признанию, CTE делают это намного лучше.

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

Если вы все-таки решите сделать это таким образом, то обязательно посмотрите Джо Селко. SQL для умников, в котором, по моему мнению, есть пара разделов, посвященных моделированию и работе с иерархиями в SQL, или, что еще лучше, приобретите его книгу, посвященную этой теме (Деревья и иерархии Джо Селко в SQL для Smarties).

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

Как правило, denormalization имеет цель быстрее querying, но приводит к увеличению пространства, увеличению DML время и, что не менее важно, активизация усилий по обеспечению согласованности данных.

Обычно код пишется быстрее (пишется быстрее, а не код быстрее), и код менее подвержен ошибкам, если данные normalized.

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

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

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

Не денормализуйте.Попытка получить хороший проект схемы путем денормализации подобна попытке добраться до Сан-Франциско, уехав из Нью-Йорка.Оно не говорит вам, куда идти.

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

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

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

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

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

Для меня настоящий вопрос: какая модель лучше подходит?

Это похоже на сравнение кортежа и списка.

  1. Кортежи имеют фиксированный размер и неоднородны — они «гипернормализованы».
  2. Списки имеют произвольный размер и однородны.

Я использую кортеж, когда мне нужен кортеж, и список, когда мне нужен список;они принципиально служат разным целям.

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

Я использую оба подхода в некоторых своих базах данных в зависимости от необходимости. Однако есть и «скрытая стоимость» рекурсивного шаблона, заключающаяся в том, что не все ORM (не уверен насчет AR) хорошо его поддерживают.Многие современные БД поддерживают «сквозные соединения» (Oracle), идентификаторы иерархии (SQL Server) или другие рекурсивные шаблоны.Другой подход — использовать иерархию на основе наборов (которая обычно опирается на триггеры/обслуживание).В любом случае, если используемый ORM плохо поддерживает рекурсивные запросы, то могут возникнуть дополнительные «затраты» на прямое использование функций БД — либо с точки зрения ручного создания запросов/представлений, либо с точки зрения управления, такого как триггеры.Если вы не используете необычный ORM или просто используете логический разделитель, такой как iBatis, то эта проблема может даже не возникнуть.

Что касается производительности на новых СУБД Oracle или SQL Server (и, вероятно, других), она должна быть очень сопоставимой, так что это будет меньше всего меня беспокоить:но ознакомьтесь с решениями, доступными для вашей СУБД и проблем с переносимостью.

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

Set1 = (Узел1 Узел2 Узел3...)

Любой узел в этом наборе также может быть другим набором, содержащим другие узлы или вложенные наборы:

Узел1=(Узел2 Узел3=(Узел4 Узел5=(Узел6) Узел7))

Как мы можем это смоделировать?Пусть у каждого узла будет два атрибута, которые задают границы содержащихся в нем узлов:

Узел = {Идентификатор:интервал, Мин:int, Макс:интервал }

Чтобы смоделировать нашу иерархию, мы просто присваиваем эти минимальные/максимальные значения соответственно:

Узел1 = { Id = 1, Мин = 1, Макс = 10 }
Узел2 = { Id = 2, Мин = 2, Макс = 2 }
Node3 = { Id = 3, Min = 3, Max = 9 }
Node4 = { Id = 4, Min = 4, Max = 4 }
Node5 = { Id = 5, Min = 5, Max = 7 }
Node6 = { Id = 6, Min = 6, Max = 6 }
Node7 = { Id = 7, Min = 8, Max = 8 }

Теперь, чтобы запросить все узлы в Set/Node5:

выберите n.* из узлов как n, узлы как s
где s.Id = 5 и s.Min < n.Min и n.Max < s.Max

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top