2015-01-06 6 views
3

У меня есть база данных SQL Server 2008 со схемой стиля снежинки, поэтому множество разных таблиц поиска, таких как Язык, Страны, Штаты, Статус и т. Д. Все эти таблицы поиска имеют почти идентичные структуры: Два столбца, код и декодирование. Мой менеджер проектов хотел бы, чтобы все эти разные таблицы были одной таблицей BIG, поэтому мне понадобится другой столбец, например CodeCategory, а мои первичные столбцы для этой большой таблицы будут CodeCategory и Code. Проблема в том, что для любой из таблиц, имеющих фактический код (например, код языка), я не могу установить отношение внешнего ключа в этой большой таблице декодирования, поскольку CodeCategory не будет в таблице фактов, а просто в коде. И коды сами по себе не будут уникальными (они будут в CodeCategory), поэтому я не могу сделать FK только из поля кода таблицы фактов в поле кода Big lookup table Code.Единая таблица поиска SQL Server

Так что я что-то упускаю, или это невозможно сделать и по-прежнему иметь возможность делать FK в связанных таблицах? Хотел бы я сделать это: у меня есть FK, где один из столбцов, которые я сопоставлял в таблице поиска, соответствовал бы константе строки. Как это (я знаю, что это невозможно, но это дает вам представление о том, что я хочу сделать):

ALTER TABLE [dbo].[Users] WITH CHECK ADD CONSTRAINT [FK_User_AppCodes] 
FOREIGN KEY('Language', [LanguageCode]) 
REFERENCES [dbo].[AppCodes] ([AppCodeCategory], [AppCode]) 

выше не работает, но если это так, я бы на FK мне нужно. Где у меня есть строка «Язык», есть ли способ в T-SQL вместо подстановки имени таблицы из кода?

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

Brian

+9

a.k.a. «Один True Lookup Table», хорошо известный * anti- * pattern. Если вы не используете какой-то странный вариант SQL Server, за который вам приходится платить за каждую таблицу, здравомыслие простых внешних ключей и более простые запросы обычно более чем перевешивают любую воспринимаемую избыточность или неэффективность. –

+2

См. [Пять простых ошибок проектирования баз данных, которые следует избегать] (https://www.simple-talk.com/sql/database-administration/five-simple--database-design-errors-you-should-avoid/) и посмотрите на пункт №1 - это именно то, что предлагает ваш премьер-министр, и его следует избегать **! –

+1

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

ответ

4

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

Хотя одна таблица поиска (как уже отмечалось) уже является действительно ужасной идеей, я скажу, что этот шаблон не требует отдельного поля PK или его автогенерации. Для этого требуется составная PK, состоящая из ([AppCodeCategory], [AppCode]), а затем в таблице фактов должны присутствовать поля BOTH, которые должны иметь составной FK обоих полей обратно в PK. Опять же, это не одобрение этой конкретной конечной цели, просто техническая нота, что возможно иметь составные ПК и FK в других, более подходящих сценариях.

Основная проблема с этим типом подхода к константам состоит в том, что каждая константа поистине является своей собственной: Языки, страны, государства, Statii и т. Д. - все это совершенно разные сущности. Хотя структура из них в базе данных такая же (на сегодняшний день), данные внутри этой структуры не представляют одинаковые вещи. Вы были бы привязаны к модели, которая либо запрещает добавлять дополнительные поля поиска позже (например, коды ISO для языка и страны, но не другие, или что-то, что относится к государствам, которые не применимы к другим), или потребует добавления полей NULLable без каких-либо способов узнать, к какой категории они применимы (получать удовольствие от вопросов отладки, связанных с этим, и/или объяснять новому человеку - который был там в течение 2 дней и ему поручено написать новый отчет), что 3 Код страны ISO не применяется к статусу «Удалено»).

Этот подход также требует, чтобы вы сохраняли произвольное поле «Категория» во всех связанных таблицах. И это за поиск. Поэтому, если у вас есть CountryCode, LanguageCode и StateCode в таблице фактов, каждый из этих FK получает соответствующее поле CategoryID, так что теперь это 6 полей вместо 3.Даже если вы смогли использовать TINYINT для CategoryID, если ваша таблица фактов имеет даже 200 миллионов строк, то эти три дополнительных 1 байтовых поля теперь занимают 600 МБ, что отрицательно сказывается на производительности. И давайте не будем забывать, что резервное копирование займет больше времени и займет больше места, но диск дешевый, не так ли? О, и если резервное копирование займет больше времени, то восстановление также займет больше времени, не так ли? О, но таблица имеет ближе к 1 миллиарду строк? Даже лучше ;-).

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

Кто-нибудь даже спросил у вашего менеджера проекта, что это за цель? Это разумный вопрос, если вы собираетесь потратить некоторое количество часов на внесение изменений в систему, чтобы заявленная выгода была потрачена на это время. Это, конечно же, не облегчает взаимодействие с данными, и на самом деле это станет сложнее, особенно если вы выберете строку для «Категории» вместо TINYINT или, может быть, SMALLINT.

Если ваш PM все еще нажимает на это изменение, то в качестве части этого проекта необходимо также соответствующим образом изменить любые enum s в коде приложения, чтобы они соответствовали тому, что находится в базе данных. Поскольку база данных имеет свои значения, сгруппированные вместе, вы можете выполнить это на C# (если ваш код приложения находится на C#, если нет, то переведите на все, что подходит), установив значения enum явно с образцом первых X цифр «категория», а остальные Y-цифры являются «значением». Например:

Предположим, что рабочий "Страна" категории == 1 и "Язык" == 2: категория, вы можете сделать:

enum AppCodes 
{ 
    // Countries 
    United States = 1000001, 
    Canada   = 1000002, 
    Somewhere Else = 1000003, 

    // Languages 
    EnglishUS = 2000001, 
    EnglishUK = 2000002, 
    French = 2000003 
}; 

Абсурд? Полностью. Но также аналогично запросу объединить все таблицы поиска в одну таблицу. Что хорошего для гуся, хорошо для гусака, верно?

+1

Спасибо, много хороших моментов, надеюсь, вы не против, если я их использую. Как архитектор и дизайнер, так и разработчик, я согласен с тем, что PMs выполняют свою работу и придерживаются ИТ! Большое спасибо. – user3772397

+0

@ user3772397 проблем нет. В конце я обновил немного больше, чтобы _might_ помог поставить перспективы в будущее. –

+1

Ваш ответ намного лучше, чем мой, я удалил свою. – HLGEM

0

Предлагается ли это, чтобы вы могли свести к минимуму количество экранов администратора, которые необходимы для операций CRUD на ваших постоянных данных? Я был здесь раньше и решил, что лучше/безопаснее/проще создать общий экран, в котором используются метаданные, чтобы решить, какую таблицу извлечь из/писать. Это было немного больше работы по созданию, но сохранила схему базы данных «правильно».

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

Смежные вопросы