Шаблон "одиночка" имеет несколько преимуществ перед статическими классами. Во-первых, одиночный элемент может расширить классы и реализовать интерфейсы, в то время как статический класс не может (он может расширить классы, но он не наследовал их членов экземпляра). Одиночный элемент может быть инициализирован лениво или асинхронно в то время как статический класс обычно инициализируется, когда он сначала загружается, ведя к потенциальным проблемам загрузчика класса. Однако самое важное преимущество, тем не менее, состоит в том, что одиночные элементы могут быть обработаны полиморфно, не вынуждая их пользователей предположить, что существует только один экземпляр.
Я думаю, что выбор наличия этих полей не причинит вам вреда сегодня, и я бы выбрал именно этот вариант. просто помните, что по мере развития вашей базы данных вам может потребоваться принять решение о рефакторинге до двух отдельных таблиц (если вам нужно больше полей)
То, что вы описываете с помощью одной таблицы для общих столбцов и зависимых таблиц для столбцов, зависящих от подтипа, называется Наследование таблицы классов . Это очень хорошо.
То, что, кажется, описывает @Scott Ferguson (две отдельные таблицы для двух типов продаж), называется Наследование конкретных таблиц . Это также может быть хорошим решением в зависимости от ваших потребностей, но чаще всего это просто затрудняет написание запроса для обоих подтипов.
Если все, что вам нужно, это один или два столбца, которые применяются только к данному подтипу, я согласен с этим кажется излишним создавать зависимые таблицы. Помните, что большинство производителей баз данных SQL поддерживают ограничения или триггеры CHECK
, поэтому вы можете создавать правила целостности данных в метаданных.
CREATE TABLE Sales (
sale_id SERIAL,
is_business INT NOT NULL, -- 1 for corporate, 0 for personal
sku VARCHAR(20), -- only for corporate
paypal_id VARCHAR(20), -- mandatory but only for personal
CONSTRAINT CHECK (is_business = 0 AND paypal_id IS NOT NULL)
);
Некоторые настаивают, что неприменимые поля никогда не должны быть разрешены, но я думаю, что это одно из тех правил, которые кто-то написал в книге, и теперь мы все должны следовать ему, не задавая вопросов. Почему. В случае, который вы описываете, одна таблица звучит как простое и разумное решение.
Я бы определенно не стал создавать две таблицы. Тогда все общие поля будут дублированы, и все ваши запросы должны будут объединить или объединить две таблицы. Итак, реальный вопрос: один стол или три. Но вы, кажется, это понимаете.
Вы не уточнили, что это за дополнительные поля. Если наличие или отсутствие одного поля подразумевает тип записи, то я иногда использую этот факт как индикатор типа записи, а не создаю избыточный тип. Мол, если единственная разница между "личной продажей" а «продажа бизнеса» означает, что при продаже бизнеса указан внешний ключ компании, тогда вы можете просто указать, что вы определяете продажу бизнеса как продажу компании, и двусмысленность невозможна. Но если ситуация немного усложняется, это может быть ловушкой: я видел приложения, которые говорят, что если a равно нулю и b = cd / 7 =, то это запись типа A, иначе, если b равно нулю и т.д. вы не можете сделать это с помощью одного теста в одном поле, забудьте об этом и введите поле типа записи.
Вы всегда можете обеспечить согласованность с помощью кода или ограничений.
Меня гораздо больше беспокоит избыточность данных, создающая проблемы согласованности затем неприменимые поля. Избыточные данные создают всевозможные проблемы. Данные неприменимы к типу записи? В худшем случае просто проигнорируйте это. Если это "личная продажа" и каким-то образом компания была заполнена, игнорируя это или обнуляя ее сразу же. Проблема решена.
Если есть две отдельные сущности, «Персональные продажи» и «Продажи компании», то, возможно, вам следует иметь две таблицы для представления этих сущностей?
Новости: база данных не может предотвратить 100% поврежденных данных, теперь независимо от того, каким образом вы их удалите. До сих пор вы рассматривали только то, что я называю коррупцией уровня 1 (повреждение уровня 0 - это, по сути, то, что могло бы произойти, если бы вы написали мусор поверх своей базы данных с помощью шестнадцатеричного редактора).
Мне еще предстоит увидеть базу данных, которая могла бы предотвратить повреждение уровня 2 (синтаксически правильные записи, но в целом означают нечто неверное).
PRO
для хранения всех полей в одной таблице заключается в том, что вы избавляетесь от JOIN
, что делает ваши запросы быстрее.
ПРОТИВОСТОЯНИЕ
заключается в том, что ваша таблица становится больше, что замедляет выполнение ваших запросов.
Какой из них влияет на вас больше, полностью зависит от вашего распределения данных и от того, какие запросы вы отправляете чаще всего.
В общем, разделение - это лучше для OLTP
систем, объединение лучше для анализа данных (который имеет тенденцию сканировать таблицы).
Давайте представим 2
сценария:
Разделить поля. Имеется 1 000 000
строк, средний размер строки составляет 20
байт, поле разделения заполняется один раз на 50
строк (т.е. 20 000
записей в разделенной таблице).
Мы хотим сделать следующий запрос: ИЗ основного стола LEFT JOIN разделенный ВКЛ splitid = mainid
Это потребует сканирования 20 000 000
байтов и вложенных циклов (или хеш-запросов), чтобы найти 10 000
записей.
Каждый хэш-поиск примерно эквивалентен сканированию 10
строк, поэтому общее время будет эквивалентно сканированию 20 000 000 + 10 * 20 000 * 20 = 24 000 000
байт
объединенных полей. Имеется 1 000 000
строк, средний размер строки составляет 24
байта, поэтому запрос будет сканировать 24 000 000
байтов.
Как видите, времена связаны .
Однако, если один из параметров изменится (поле заполняется чаще или реже, размер строки больше или меньше и т. Д.), То то или иное решение станет лучше.