Какова наилучшая практика для первичных ключей в таблицах?

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

  • Идентификатор целочисленного столбца, который автоматически увеличивается.
  • Уникальный идентификатор (GUID)
  • Столбец с коротким символом (x) или целочисленным (или другим относительно небольшим числовым типом), который может служить столбцом идентификатора строки

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

По большей части все остальные таблицы будут либо иметь первичный ключ с автоматическим приращением целых чисел или уникальный идентификатор.

Вопрос: -)

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

  • Дата и время/символ
  • DateTime/целое число
  • Дата и время /VARCHAR
  • char/NVARCHAR/NVARCHAR

Есть ли для этого действительный случай? Я бы всегда определял столбец идентификатора или уникального идентификатора для этих случаев.

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

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

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

Ответ 1

Я следую нескольким правилам:

  • Первичные ключи должны быть как можно меньше. Предпочитайте числовой тип, потому что числовые типы хранятся в гораздо более компактном формате, чем форматы символов. Это связано с тем, что большинство первичных ключей будут внешними ключами в другой таблице, а также используются в нескольких индексах. Чем меньше ваш ключ, тем меньше индекс, тем меньше страниц в кеше вы будете использовать.
  • Первичные ключи никогда не должны меняться. Обновление первичного ключа всегда должно быть исключено. Это связано с тем, что он, скорее всего, будет использоваться в нескольких индексах и использоваться как внешний ключ. Обновление одного первичного ключа может вызвать эффект изменения пульсаций.
  • НЕ используйте "ваш первичный ключ проблемы" в качестве первичного ключа логической модели. Например, номер паспорта, номер социального страхования или номер контракта сотрудника, так как этот "первичный ключ" может измениться для ситуаций реального мира.

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

Ответ 2

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

  • США: я бы пошел на state_code ( "TX" для Texas и т.д.), а не state_id = 1 для Texas
  • Сотрудники: Обычно я создаю искусный employee_id, потому что трудно найти что-нибудь еще, что работает. SSN или эквивалент могут работать, но могут возникнуть проблемы, такие как новый столяр, который еще не предоставил свой SSN.
  • История окладов сотрудников: (employee_id, start_date). Я бы не создал искусственный employee_salary_history_id. Какая точка будет служить (кроме "глупая согласованность" )

В тех случаях, когда используются искусственные ключи, вы всегда должны также объявлять уникальные ограничения для естественных ключей. Например, используйте state_id, если нужно, но тогда вам лучше объявить уникальное ограничение для state_code, иначе вы обязательно получите:

state_id    state_code   state_name
137         TX           Texas
...         ...          ...
249         TX           Texas

Ответ 3

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

Скажем, у нас есть эти таблицы и столбцы:

Company:
  CompanyId   (primary key)

CostCenter:
  CompanyId   (primary key, foreign key to Company)
  CostCentre  (primary key)

CostElement
  CompanyId   (primary key, foreign key to Company)
  CostElement (primary key)

Invoice:
  InvoiceId    (primary key)
  CompanyId    (primary key, in foreign key to CostCentre, in foreign key to CostElement)
  CostCentre   (in foreign key to CostCentre)
  CostElement  (in foreign key to CostElement)

В случае, если последний бит не имеет смысла, Invoice.CompanyId является частью двух внешних ключей, один для таблицы CostCentre и один для таблицы CostElement. Первичный ключ (InvoiceId, CompanyId).

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

Чем меньше шансов испортить, тем лучше.

Ответ 4

Я избегаю использования естественных ключей по одной простой причине - человеческой ошибке. Хотя доступны уникальные уникальные идентификаторы (SSN, VIN, номер счета и т.д.), Они требуют, чтобы человек правильно их вводил. Если вы используете SSN в качестве первичного ключа, кто-то переносит пару цифр во время ввода данных, и ошибка не будет обнаружена сразу, тогда вы столкнулись с изменением вашего первичного ключа.

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

Ответ 5

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

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

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

Но нет никакого оправдания отсутствием ключа.

RE: EDIT

Да, в этом много споров: D

Я не вижу очевидного преимущества в естественных ключах, кроме того, что они являются естественным выбором. Вы всегда будете думать в Name, SocialNumber - или что-то в этом роде - вместо idPerson.

Суррогатные ключи - это ответ на некоторые из проблем, которые имеют естественные ключи (например, распространение изменений).

Как вы привыкли к суррогатам, кажется более чистым и управляемым.

Но в конце концов, вы узнаете, что это просто вопрос вкуса - или мышления. Люди "думают лучше" с естественными ключами, а другие - нет.

Ответ 6

Таблицы должны иметь первичный ключ все время. Когда это не так, это должны быть поля AutoIncrement.

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

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

Ответ 7

Что особенного в первичном ключе?

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

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

  • ASIDE: К сожалению, побочный эффект большинства создаваемых баз данных и разработанные программистами приложений (которые я иногда) что лучше всего подходит для прикладной или прикладной среды управляет выбором первичного ключа для таблиц. Это приводит к целым и GUID (поскольку они просты в использовании для фреймворков приложений) и монолитных табличных конструкций (поскольку они уменьшают количество приложений объекты инфраструктуры, необходимые для представления данных в памяти). Эти приложения, основанные на приложениях, приводят к значительным данным проблемы согласованности при использовании в масштабе. Рамки приложений спроектированные таким образом, естественно приводят к таблице во времени. "Частичные записи" создаются в таблицах и заполненных данных со временем. Взаимодействие с несколькими таблицами избегается или при использовании вызывает непоследовательность когда приложение работает неправильно. Эти проекты приводят к данным, которые не имеют смысла (или их трудно понять), распространению данных над таблицами (вы должны посмотреть на другие таблицы, чтобы понять текущая таблица) и дублированные данные.

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

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

Сказав это, я благодарен за многие плохо разработанные базы данных, которые существуют сегодня в бизнесе (бессмысленные суррогатные-искаженные данные-поврежденные-1NF-гиганты), потому что это означает, что существует бесконечная работа для людей, которые понимают правильный дизайн базы данных. Но с грустной стороны иногда это заставляет меня чувствовать себя Сизифом, но я уверен, что у него было чертовски 401 тыс. (До крушения). Держитесь подальше от блогов и веб-сайтов для важных вопросов по дизайну базы данных. Если вы разрабатываете базы данных, найдите CJ Date. Вы также можете ссылаться на Celko для SQL Server, но только если вы сначала держите нос. На стороне Oracle обратитесь к Tom Kyte.

Ответ 8

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

Просто процитируем несколько моментов:

Разработчик должен применять несколько правил при выборе первичного ключа для каждой таблицы:

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

Природные ключи (имеют тенденцию) нарушают правила. Суррогатные ключи соответствуют правилам. (Вам лучше прочитать эту статью, это стоит вашего времени!)

Ответ 9

Естественный ключ, если он доступен, обычно лучше всего. Итак, если datetime/ char однозначно идентифицирует строку, и обе части имеют значение для строки, это замечательно.

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

Ответ 10

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

"Каждый клиент в моей базе данных будет и должен иметь SSN". Бам, сделанный, сделай его первичным ключом и сделай с ним. Просто помните, когда изменилось ваше бизнес-правило.

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

Ответ 11

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

В качестве альтернативы, GUIDs в качестве первичного ключа может быть свистком производительности. Я бы не рекомендовал его.

Ответ 12

Вы должны использовать первичный ключ "составной" или "составной", который состоит из нескольких полей.

Это вполне приемлемое решение, перейдите здесь для получения дополнительной информации:)

Ответ 13

Я тоже всегда использую числовой идентификатор. В оракуле я использую число (18,0) без реальной причины выше числа (12,0) (или что-то вроде int, а не длинного), может быть, я просто не хочу волноваться о том, чтобы получить несколько миллиардов строк в db!

Я также включаю созданный и измененный столбец (тип timestamp) для основного отслеживания, где это кажется полезным.

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

Ответ 14

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

Если никакие естественные ключи не найдены, я предпочитаю GUID для INT ++, потому что SQL Server использует деревья, и плохо всегда добавлять ключи к концу в деревьях.

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

Поскольку мне посчастливилось использовать SQL Server, я могу изучить планы выполнения и статистику с помощью профилировщика и анализатора запросов и узнать, как мои клавиши работают очень легко.

Ответ 15

Я всегда использую поле autonumber или identity.

Я работал на клиента, который использовал SSN в качестве первичного ключа, а затем из-за правил HIPAA был вынужден перейти на "MemberID", и это вызвало массу проблем при обновлении внешних ключей в связанных таблицах. Придерживание согласованного стандарта столбца идентификации помогло мне избежать аналогичной проблемы во всех моих проектах.

Ответ 16

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

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

Ответ 17

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

Ответ 18

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

Вам нужно создать идентификаторы COMB. Хорошая статья об этом и статистика производительности Стоимость GUID как первичных ключей.

Также некоторый код построения GUID GUID в SQL находится в Uniqueidentifier vs identity (archive).

Ответ 19

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

Ответ 20

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

  • Идентификатор строки (GUID)
  • Создатель (строка; имеет значение по умолчанию для текущего имени пользователя (SUSER_SNAME() в T-SQL))
  • Создано (DateTime)
  • Отметка

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

Между тем, фактический ПК, по возможности, является естественным ключом. Мои внутренние правила - это что-то вроде:

  • Люди - используют суррогатный ключ, например. INT. Если он внутренний, пользовательский GUID Active Directory является приемлемым выбором.
  • Таблицы поиска (например, StatusCodes) - используйте короткий CHAR код; это легче запомнить, чем INT, и во многих случаях бумажные формы и пользователи также будут использовать его для краткости (например, Status = "E" для "Expired", "A" для "Approved", "NADIS" для "No Asbestos Detected" В образце ")
  • Связывание таблиц - комбинация FK (например, EventId, AttendeeId)

Таким образом, вы в конечном итоге получите естественный, удобочитаемый и запоминающийся ПК и удобный для ORM идентификатор идентификатора для каждого стола.

Предостережение: базы данных, которые я поддерживаю, имеют тенденцию к 100 000s записей, а не миллионы или миллиарды, поэтому, если у вас есть опыт более крупных систем, которые противоречат моему совету, не стесняйтесь игнорировать меня!