Есть две таблицы: Deal
и DealCategories
. Одна сделка может иметь много категорий сделок.
Таким образом, правильным способом должно быть создание таблицы DealCategories
со следующей структурой:
DealCategoryId (PK)
DealId (FK)
DealCategoryId (FK)
Тем не менее, наша аутсорсинговая команда сохранила несколько категорий в Deal
таблице следующим образом:
DealId (PK)
DealCategory -- In here they store multiple deal ids separated by commas like this: 18,25,32.
Я чувствую, что то, что они сделали, неправильно, но я не знаю, как четко объяснить, почему это неправильно.
Как мне объяснить им, что это неправильно? Или может я тот, кто не прав и это приемлемо?
database-design
foreign-key
Саравут Позитвинью
источник
источник
Ответы:
Да, это ужасная идея.
Вместо того, чтобы идти:
Теперь вам нужно идти:
Затем вам нужно сделать что-то в коде приложения, чтобы разбить этот список запятых на отдельные числа, а затем запросить базу данных отдельно:
Этот дизайн антипаттерна проистекает либо из полного недопонимания реляционного моделирования (вам не нужно бояться таблиц. Таблицы - ваши друзья. Используйте их), либо из-за странного заблуждения о том, что быстрее взять список, разделенный запятыми, и разделить его. в коде приложения, чем добавить таблицу ссылок (это никогда не происходит). Третий вариант - они не уверены в себе и не достаточно компетентны в SQL, чтобы иметь возможность устанавливать внешние ключи, но в этом случае они не должны иметь ничего общего с дизайном реляционной модели.
Антипаттерны SQL (Karwin, 2010) посвящают этому антипаттерну целую главу (которую он называет «Jaywalking»), страницы 15-23. Кроме того, автор разместил на аналогичный вопрос в SO . Ключевые моменты, которые он отмечает (применительно к этому примеру):
COUNT
иSUM
т. Д.), Опять же, варьируются от «сложных» до «почти невозможных». Спросите ваших разработчиков, как они могут получить список всех категорий с подсчетом количества сделок в этой категории. При правильном дизайне это четыре строки SQL.VARCHAR
ограничениями длины списка. Хотя если у вас есть разделенный запятыми список длиной более 4000 символов, есть вероятность, что в любом случае монстр будет работать очень медленно.TLDR: это принципиально некорректный дизайн, он плохо масштабируется, он добавляет дополнительную сложность даже к самым простым запросам и сразу же из коробки замедляет работу вашего приложения.
источник
Это действительно хороший дизайн, если вам нужно только запросить категории для данной сделки.
Но это ужасно, если вы хотите знать все предложения в данной категории.
И это также делает действительно трудным и подверженным ошибкам делать что-либо еще - например, обновления, подсчеты, объединения и т. Д.
Денормализация имеет свое место, но вы должны иметь в виду, что она оптимизирует для одного типа запроса за счет всех других, которые вы можете сделать с теми же данными. Если вы знаете, что вы всегда будете запрашивать по одному шаблону, то это может дать вам преимущество в использовании денормализованного дизайна. Но если есть шанс, что вам понадобится больше гибкости в типах запросов, придерживайтесь нормализованного дизайна.
Как и при любой другой форме оптимизации, вам нужно знать, какие запросы вы собираетесь запускать, прежде чем вы сможете решить, оправдана ли денормализация.
источник
select * from DealCategories where DealId in (1,2,3,4,...)
. У вас больше опыта в отношении проектирования баз данных, чем у меня, поэтому, возможно, у вас есть веские основания в некоторых случаях для такой «экстремальной настройки» в очень специфических случаях. Моя единственная идея оправдать это - очень высокаяselect
нагрузка на Deal / DealCategory. Для меня это очень похоже на то, что какая-то внешняя команда, не обладающая какими-либо знаниями в области разработки БД, помимо создания таблиц, создала ее.Несколько значений в столбце соответствуют первой нормальной форме.
Это также абсолютно не увеличивает скорость, поскольку таблицы должны быть связаны в базе данных. Вы должны сначала прочитать и проанализировать строку, а затем выбрать все категории для «Сделки».
Правильная реализация будет соединительной таблицей, такой как «DealDealCategories», с DealId и DealCategoryId.
Плохая реализация иерархии?
Кроме того, FK в DealCategories другой DealCategory выглядит как плохая реализация иерархии / дерева DealCategories. Работать с деревьями через отношение Parent ID (так называемый список смежности) очень сложно!
Проверяйте наличие вложенных наборов (хорошо читаемых, но трудно изменяемых) и таблиц закрытия (наилучшая общая производительность, но, возможно, высокое использование памяти - вероятно, не слишком много для ваших DealCategories) при реализации иерархий!
источник