Суррогатная мать противестественные / бизнес-ключи [закрыты]

StackOverflow https://stackoverflow.com/questions/63090

Вопрос

И вот мы снова возвращаемся к старому спору, который все еще возникает...

Было бы нам лучше иметь бизнес-ключ в качестве первичного ключа, или мы предпочли бы иметь суррогатный идентификатор (т.е.идентификатор SQL Server) с уникальным ограничением для поля бизнес-ключа?

Пожалуйста, приведите примеры или доказательства в поддержку вашей теории.

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

Решение

И то, и другое.Возьми свой пирог и съешь его.

Помните, что в первичном ключе нет ничего особенного, за исключением того, что он помечен как таковой.Это не что иное, как уникальное ограничение NOT NULL, и таблица может содержать более одной.

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

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

Всего несколько причин для использования суррогатных ключей:

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

  2. Конвенция:Позволяет вам использовать стандартизированное соглашение об именовании столбцов первичного ключа вместо того, чтобы думать о том, как объединить таблицы с различными именами для их PK.

  3. Скорость:В зависимости от значения и типа PK суррогатный ключ целого числа может быть меньше, что ускоряет индексацию и поиск.

Похоже, что никто еще ничего не сказал в поддержку не суррогатных (я не решаюсь сказать "естественных") ключей.Итак, поехали...

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

select sum(t.hours)
from timesheets t
where t.dept_code = 'HR'
and t.status = 'VALID'
and t.project_code = 'MYPROJECT'
and t.task = 'BUILD';

против:

select sum(t.hours)
from timesheets t
     join departents d on d.dept_id = t.dept_id
     join timesheet_statuses s on s.status_id = t.status_id
     join projects p on p.project_id = t.project_id
     join tasks k on k.task_id = t.task_id
where d.dept_code = 'HR'
and s.status = 'VALID'
and p.project_code = 'MYPROJECT'
and k.task_code = 'BUILD';

Если только кто-нибудь всерьез не считает следующее хорошей идеей?:

select sum(t.hours)
from timesheets t
where t.dept_id = 34394
and t.status_id = 89    
and t.project_id = 1253
and t.task_id = 77;

"Но, - скажет кто-нибудь, - что происходит, когда изменяется код для MYPROJECT, VALID или HR?" На что я бы ответил::"зачем тебе это потребность чтобы изменить это?" Это не "естественные" ключи в том смысле, что какой-то внешний орган собирается законодательно установить, что отныне "ДЕЙСТВИТЕЛЬНЫЙ" должен быть перекодирован как "ХОРОШИЙ".Только небольшой процент "естественных" ключей действительно попадает в эту категорию - SSN и почтовый индекс являются обычными примерами.Я бы определенно использовал бессмысленный цифровой ключ для таких таблиц, как Person, Address, но не для все, за который по какой-то причине выступает большинство присутствующих здесь людей.

Смотрите также: мой ответ на другой вопрос

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

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

Думайте о Компаниях:вы - счастливая компания Merkin, ведущая бизнес с другими компаниями Меркии.Вы достаточно умны, чтобы не использовать название компании в качестве первичного ключа, поэтому вы используете уникальный идентификатор компании правительства Меркии, состоящий всего из 10 буквенно-цифровых символов.Затем Merkia меняет идентификаторы компаний, потому что они подумали, что это будет хорошей идеей.Все в порядке, вы используете функцию каскадных обновлений вашего движка базы данных для изменений, которые в первую очередь не должны касаться вас.Позже ваш бизнес расширяется, и теперь вы работаете с компанией во Фридонии.Идентификатор компании Freedonian может содержать до 16 символов.Вам необходимо увеличить первичный ключ идентификатора компании (также поля внешнего ключа в Заказах, Выдаче, денежных переводах и т.д.), добавив поле страны в первичный ключ (также во внешних ключах).Ой!Гражданская война во Фридонии, она расколота на три страны.Название страны вашего партнера должно быть изменено на новое;каскадные обновления приходят на помощь.Кстати, какой у вас первичный ключ?(Страна, идентификатор компании) или (Идентификатор компании, Страна)?Последнее помогает объединяться, первое позволяет избежать другого индекса (или, возможно, многих других, если вы хотите, чтобы ваши Заказы тоже были сгруппированы по странам).

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

У суррогатного ключа НИКОГДА не будет причин для изменения.Я не могу сказать того же о естественных ключах.Фамилии, электронные адреса, номера ISBN - все это может измениться в один прекрасный день.

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

Вот мои причины:

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

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

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

  4. В цепочках отношений "один ко многим" - логических цепочках ключей.Так, например, Организации имеют много Учетных записей, а Учетные записи имеют много Счетов-фактур.Таким образом, логическим ключом Organization является OrgName .Логическим ключом учетных записей является OrgName, AccountId.Логическим ключом счета-фактуры является OrgName, AccountId, InvoiceNumber.

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

  5. Хранение суррогатных значений ключей в таблицах подстановки приводит к заполнению таблиц бессмысленными целыми числами.Для просмотра данных необходимо создать сложные представления, которые присоединяются ко всем таблицам подстановки.Таблица подстановки предназначена для хранения набора допустимых значений для столбца.Он не должен быть кодифицирован путем сохранения вместо него целочисленного суррогатного ключа.В правилах нормализации нет ничего, что предполагало бы, что вы должны хранить суррогатное целое число вместо самого значения.

  6. У меня есть три разные базы данных.Ни на одном из них не показано использование суррогатных ключей.

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

Поскольку кажется, что многие люди представляют суррогатные ключи как почти идеальное решение, а естественные ключи - как чуму, я сосредоточусь на аргументах другой точки зрения:

Недостатки суррогатных ключей

Суррогатными ключами являются:

  1. Источник проблем с производительностью:
    • Обычно они реализуются с использованием автоматически увеличиваемых столбцов, которые означают:
      • Повторяйте обращение к базе данных каждый раз, когда вы хотите получить новый идентификатор (я знаю, что это можно улучшить, используя алгоритмы кэширования или [seq], похожие на hilo, но все же у этих методов есть свои недостатки).
      • Если однажды вам понадобится переместить ваши данные из одной схемы в другую (по крайней мере, в моей компании это происходит довольно регулярно), то вы можете столкнуться с проблемами коллизии идентификаторов.И да, я знаю, что вы можете использовать UUID, но для этого требуется 32 шестнадцатеричных цифры!(Если вас волнует размер базы данных, то это может быть проблемой).
      • Если вы используете одну последовательность для всех ваших суррогатных ключей, то - наверняка - у вас возникнет конфликт в вашей базе данных.
  2. Подвержен ошибкам.Последовательность имеет ограничение max_value, поэтому - как разработчик - вы должны обратить внимание на следующие моменты:
    • Вы должны циклически изменять свою последовательность (при достижении максимального значения она возвращается к 1,2, ...).
    • Если вы используете последовательность как упорядочение (по времени) ваших данных, то вы должны обработать случай циклирования (столбец с идентификатором 1 может быть новее, чем строка с идентификатором max-value - 1).
    • Убедитесь, что ваш код (и даже ваши клиентские интерфейсы, которые не должны выполняться, поскольку это должен быть внутренний идентификатор) поддерживает 32b / 64b целых чисел, которые вы использовали для хранения значений вашей последовательности.
  3. Они не гарантируют отсутствие дублирования данных.У вас всегда может быть 2 строки с одинаковыми значениями столбцов, но с другим сгенерированным значением.Для меня это ТОТ САМЫЙ проблема суррогатных ключей с точки зрения проектирования базы данных.
  4. Подробнее в Википедии...

Мифы о природных ключах

  1. Составные ключи менее неэффективны, чем суррогатные ключи.Нет!Это зависит от используемого ядра базы данных:
  2. Естественных ключей в реальной жизни не существует.Извините, но они действительно существуют!В авиационной промышленности, например, следующий кортеж всегда будет уникальным относительно данного запланированный рейс (авиакомпания, дата вылета, номер рейса, оперативный номер).В более общем плане, когда набор бизнес-данных гарантированно уникален для данного стандартный тогда этот набор данных является [хорошим] естественным кандидатом на получение ключа.
  3. Естественные ключи "загрязняют схему" дочерних таблиц.Для меня это скорее чувство, чем реальная проблема.Наличие первичного ключа из 4 столбцов по 2 байта в каждом может быть более эффективным, чем один столбец из 11 байт.Кроме того, 4 столбца можно использовать для прямого запроса дочерней таблицы (используя 4 столбца в предложении where) без присоединения к родительской таблице.

Заключение

Используйте естественные ключи, когда это уместно, и используйте суррогатные ключи, когда их лучше использовать.

Надеюсь, что это кому-то помогло!

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

Редактировать:Я пытался найти ссылку на это в Интернете, но не смог.Однако в "Шаблоны архитектуры предприятия" [Фаулер] там есть хорошее объяснение, почему вы не должны использовать ничего, кроме ключа, не имеющего иного значения, кроме того, что он является ключом.Это сводится к тому, что у него должна быть одна работа, и только одна.

Суррогатные ключи довольно удобны, если вы планируете использовать инструмент ORM для обработки / генерации ваших классов данных.В то время как вы можете использовать составные ключи с некоторыми из более продвинутых картографов (читать:hibernate), это добавляет некоторую сложность вашему коду.

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

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

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

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

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

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

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

Бизнес-логика / естественные ключи могут меняться, но физический ключ таблицы НИКОГДА не должен меняться.

В сценарии хранилища данных, я считаю, лучше следовать пути суррогатного ключа.Две причины:

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

Суррогатные ключи могут быть полезны, когда деловая информация может измениться или быть идентичной.В конце концов, названия компаний не обязательно должны быть уникальными по всей стране.Предположим, вы имеете дело с двумя компаниями под названием Smith Electronics, одной в Канзасе и одной в Мичигане.Вы можете отличать их по адресу, но это изменится.Даже состояние может измениться;что, если Smith Electronics из Канзас-Сити, штат Канзас, переедет через реку в Канзас-Сити, штат Миссури?Не существует очевидного способа разграничить эти компании с помощью естественной ключевой информации, поэтому суррогатный ключ очень полезен.

Думайте о суррогатном ключе как о номере ISBN.Обычно вы идентифицируете книгу по названию и автору.Однако у меня есть две книги под названием "Перл-Харбор" Х.P.Уилмотт, и это определенно разные книги, а не просто разные издания.В подобном случае я мог бы сослаться на внешний вид книг или на сравнение более ранних с более поздними, но хорошо, что у меня есть ISBN, на который я могу опереться.

Напоминаю, что не рекомендуется размещать кластеризованные индексы на случайных суррогатных ключах, т. е.Идентификаторы GUID, которые читают XY8D7-DFD8S, поскольку они не позволяют SQL Server физически сортировать эти данные.Вместо этого вам следует поместить уникальные индексы в эти данные, хотя может быть также полезно просто запустить SQL profiler для основных табличных операций, а затем поместить эти данные в советник по настройке ядра базы данных.

Смотрите поток @ http://social.msdn.microsoft.com/Forums/en-us/sqlgetstarted/thread/27bd9c77-ec31-44f1-ab7f-bd2cb13129be

Случай 1: Ваш стол - это справочная таблица с менее чем 50 типами (вставок)

Использование бизнес/естественные ключи.Например:

Table: JOB with 50 inserts
CODE (primary key)       NAME               DESCRIPTION
PRG                      PROGRAMMER         A programmer is writing code
MNG                      MANAGER            A manager is doing whatever
CLN                      CLEANER            A cleaner cleans
...............
joined with
Table: PEOPLE with 100000 inserts

foreign key JOBCODE in table PEOPLE
looks at
primary key CODE in table JOB

Случай 2: Ваш стол - это таблица с тысячами вставок

Использование суррогатные/автоинкрементные ключи.Например:

Table: ASSIGNMENT with 1000000 inserts
joined with
Table: PEOPLE with 100000 inserts

foreign key PEOPLEID in table ASSIGNMENT
looks at
primary key ID in table PEOPLE (autoincrement)

В первом случае:

  • Вы можете выбрать всех программистов в таблице PEOPLE без использования join with table JOB, а просто с помощью:"ВЫБЕРИТЕ * ИЗ СПИСКА ЛЮДЕЙ, ГДЕ JOBCODE = 'PRG'"

Во втором случае:

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

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

Лошадь для курсов.Чтобы заявить о своей предвзятости;В первую очередь я разработчик, поэтому меня в основном интересует предоставление пользователям работающего приложения.

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

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

Большинству традиционных разработчиков PL / SQL, с которыми я работал, не нравились суррогатные ключи из-за количества таблиц на объединение, но наши тестовые и производственные базы данных никогда не вызывали беспокойства;дополнительные объединения не повлияли на производительность приложения.С диалектами базы данных, которые не поддерживают предложения типа "X inner join Y on X.a = Y.b", или разработчиками, которые не используют этот синтаксис, дополнительные объединения для суррогатных ключей затрудняют чтение запросов и увеличивают время ввода и проверки:смотрите сообщение @Tony Andrews.Но если вы используете ORM или любой другой фреймворк для генерации SQL, вы этого не заметите.Сенсорный ввод текста также смягчает ситуацию.

Возможно, это не совсем относится к этой теме, но у меня возникает головная боль, связанная с суррогатными ключами.Предварительно поставляемая Oracle analytics создает автоматически сгенерированные SKK для всех своих таблиц измерений в хранилище, а также сохраняет их в фактах.Таким образом, всякий раз, когда их (измерения) необходимо перезагружать по мере добавления новых столбцов или заполнения для всех элементов в измерении, SKS, назначенные во время обновления, не синхронизируют SKS с исходными значениями, сохраненными в fact, что приводит к полной перезагрузке всех таблиц фактов, которые присоединяются к нему.Я бы предпочел, чтобы, даже если SK было бессмысленным числом, был бы какой-то способ, которым оно не могло бы измениться для оригинальных / старых записей.Как многие знают, готовые решения редко удовлетворяют потребностям организации, и нам приходится постоянно их настраивать.Теперь у нас в хранилище данных на 3 года больше, и полная перезагрузка Oracle Financial systems занимает очень много времени.Таким образом, в моем случае они не генерируются на основе ввода данных, а добавляются в хранилище, чтобы помочь отчитаться о производительности.Я понимаю, но наши отношения меняются, и это настоящий кошмар.

В случае базы данных на определенный момент времени лучше всего иметь комбинацию суррогатных и естественных ключей.например ,вам необходимо отслеживать информацию о члене клуба.Некоторые атрибуты участника никогда не меняются.например, дата рождения, но имя может измениться.Итак, создайте таблицу членов с суррогатным ключом member_id и создайте столбец для DOB.Создайте другую таблицу с именем person name и добавьте столбцы для member_id, member_fname, member_lname, date_updated.В этой таблице естественным ключом будет member_id + date_updated .

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