Должна ли каждая таблица иметь суррогатный / искусственный первичный ключ для одного поля?

33

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

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

Чтобы быть ясным, этот вопрос не об искусственном против естественного - а о том, все ли искусственные ключи должны быть однополевыми

Джек Дуглас
источник
1
см. также dba.stackexchange.com/a/112632/1396
Джек Дуглас,

Ответы:

28

Я собираюсь сказать нет, не всегда, но в большинстве случаев да. ,

Вот некоторые обстоятельства, при которых вам не нужен суррогатный или искусственный ключ:

  • Чистые таблицы пересечений . Если нет риска, что пересечение будет целью внешнего ключа, и если риск пересечения привлекает независимые атрибуты (то есть что-то отличное от FK для двух родительских таблиц), или нет, то вы можете избежать использования комбинации ФК как ПК с честной уверенностью.
  • Поиск таблиц со статическими бизнес-ключами . Если у вас есть справочная
    таблица с уникальным бизнес-ключом, который внешне привязан к вашему
    бизнесу и у которого нет никаких шансов когда-либо измениться для каких-либо
    практических целей, то прямое использование бизнес-ключа может упростить
    ситуацию. Примером может быть список
    кодов штатов или провинций или список стандартных номеров ANSI и т. Д.
  • Таблицы, содержащие данные, объединенные из нескольких независимых источников . Если в вашей системе много источников данных, которые необходимо объединить в единую таблицу, скажем, в головном офисе, то иногда вам нужен составной ключ, который включает значение ключа системы источника и код, указывающий, какой была исходная система.

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

  • Ситуации, когда вам необходимо объединить данные из нескольких независимых источников. Чтобы избежать коллизий ключей, вы можете использовать GUID вместо ключей IDENTITY.
  • Ситуации, когда вы вынуждены использовать нечисловые представления ключей. Допустим, у вас есть база данных номерных знаков. Ваш ключ может быть буквенно-цифровым значением вместо чистого числа.
  • Ситуации, когда некоторые внешние требования вынуждают вас применять сжатие к значению вашего ключа. Вместо использования 10 цифр для int32 вы можете использовать шесть базовых 36 цифр.

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

Сказав это, помните, что для YAGNI есть место для применения этой концепции. Вам не нужно вводить кодовые таблицы с ключами IDENTITY в каждый закоулок вашей схемы, на тот случай, если кто-то решит, что символ мужского пола в вашей таблице сотрудников должен измениться с M на X или что-то глупое.

Джоэл Браун
источник
«Использование суррогатного ключа удержит вас от попадания в эту ловушку». Вопрос не в суррогате против естественного, а в однополевом или многопольном.
Джек Дуглас
Как вы признали в комментарии к своему собственному ответу, мы находимся на территории «согласен не соглашаться», когда речь идет о том, что разумно при разработке базы данных. Учитывая ваше редактирование, я бы не делал различий между суррогатными и естественными ключами, поэтому моя вторая точка зрения запоздало не по теме. Мои другие пункты относительно того, когда можно отклониться от классического подхода «идентичность / последовательность», остаются в силе.
Джоэл Браун
Я не изменил вопрос, как вы можете видеть из истории, просто добавил акцент, где я думал, что это поможет ским-читателям
Джек Дуглас,
12

Нет.

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

Я попытаюсь проиллюстрировать мою точку зрения в следующих примерах, в которых:

  • brand автомобиль марки, например, Ford, Toyota и т. д.
  • dealer является физическим дилером, привязанным к бренду (например, дилерский центр Ford, продающий только Форды)
  • model это тип автомобиля, например, Ford Focus, Ford Fiesta и т. д.
  • stock текущее количество автомобилей для каждого автосалона

Если мы создадим суррогатный ключ для одного поля для dealerи modelследующим образом:

create table brand( brand_id integer primary key );

create table dealer( dealer_id integer primary key, 
                     brand_id integer references brand )

create table model( model_id integer primary key, 
                    brand_id integer references brand )

create table stock( model_id integer references model, 
                    dealer_id integer references dealer, 
                    quantity integer,
                      primary key(model_id, dealer_id) )

тогда можно вставить строку stock, связывающую «Форд dealer» с моделью «Тойота». Добавление brand_id references brandк stockтолько усугубляет проблему. С другой стороны, если мы сохраним внешний ключ как часть первичного ключа следующим образом:

create table brand( brand_id integer primary key );

create table dealer( brand_id integer references brand, 
                     dealer_id integer, 
                       primary key(brand_id, dealer_id) )

create table model( brand_id integer references brand, 
                    model_id integer, 
                      primary key(brand_id, model_id) )

create table stock( brand_id integer, 
                    model_id integer, 
                    dealer_id integer, 
                    quantity integer,
                      primary key(brand_id, model_id, dealer_id),
                      foreign key(brand_id, model_id) references model,
                      foreign key(brand_id, dealer_id) references dealer )

Теперь правило о том, что дилеры «Форда» могут покупать только автомобили «Форда», естественным образом обеспечивается моделью.

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

create table dealer( brand_id integer references brand, 
                     dealer_id serial unique, 
                       primary key(brand_id, dealer_id) )
Джек Дуглас
источник
3
Принимая во внимание обычные оговорки о том, что примеры не обязательно являются идеальными со всех сторон, я бы сказал, что этот тип дизайна является особенно хрупким. Хотя есть что-то удовлетворяющее в поиске способа использования DRI для обеспечения соблюдения бизнес-правил, оно также лишает вас возможности реагировать на изменения. Если Toyota купит Ford или даже если дилер Ford решит продать подержанную Toyota, ваши бизнес-правила, основанные на DRI, приведут к головной боли при обслуживании.
Джоэл Браун
1
Так что «ваши бизнес-правила могут измениться». Это верно для любого бизнес-правила, и его всегда будет сложно изменить. Мне обычно говорят, что такое бизнес-правила - я не решаю их для себя.
Джек Дуглас
1
Вы хотите сказать, что DRI вообще не должен использоваться для обеспечения соблюдения бизнес-правил? Разве это не единственное, что делает DRI? - даже простые внешние ключи являются бизнес-правилами, применяемыми DRI.
Джек Дуглас
4
Конечно, DRI обеспечивает соблюдение бизнес-правил. Вы должны решить, какие правила будут применяться в коде, а какие в вашей схеме. Изменения схемы почти всегда сложнее, чем изменения кода. Существует два вида бизнес-правил, которые могут войти в вашу модель данных. Один там, а другой нет. Фундаментальный характер данных, которые важны для вашего бизнеса, не сильно меняется. Конкретные способы работы с этими данными гораздо более изменчивы . Правило, как у автомобилей, принадлежит производителю в модели данных. Как правило, дилеры никогда не будут продавать автомобили двух марок.
Джоэл Браун
4
«Изменения схемы почти всегда сложнее, чем изменения кода» ИМО, наоборот. На самом деле я не согласен практически со всем, что вы только что сказали, но я сомневаюсь, что есть смысл спорить с вами, так что я оставлю это на этом.
Джек Дуглас
12

"это зависит"

Да: суррогатные поля IDENTITY / AUTONUMBER хороши, когда натуральный ключ широкий и не числовой. Примечание: это предполагает смешение «PK» и кластерного индекса, которое происходит по умолчанию в SQL Server, Sybase и т. Д.

Нет: много / много таблиц, когда достаточно 2 родительских ключей. Или когда натуральный ключ короткой и фиксированной длины, например, код валюты

Конечно, мозговой мертвец ORM (читай: (n) Hibernate) может превзойти эти правила ...

Изменить: чтение вопроса снова

Таблица много / много с двумя суррогатными родительскими ключами будет иметь несколько столбцов PK.
Однако, это не нуждается в другой суррогатной колонке.

Если в таблице есть суррогатный ключ (IDENTITY и т. Д.), То он не обязательно должен содержать несколько столбцов.

У вас может быть супер-ключ, который включает суррогат, но это будет обеспечивать применение других правил (например, подтипов )

ГБН
источник