Как вам ваши первичные ключи? [закрыто]


88

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

  1. Int / BigInt, автоинкремент которых является достаточно хорошими первичными ключами.
  2. Должно быть не менее 3 столбцов, составляющих первичный ключ.
  3. Идентификатор, GUID и удобочитаемые идентификаторы строк следует рассматривать по-разному.

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

РЕДАКТИРОВАТЬ: у кого-нибудь есть простой образец / алгоритм для создания удобочитаемых идентификаторов для строк, которые хорошо масштабируются?


1
Поскольку это субъективно, это должна быть вики сообщества
Джон Шиэн

2
«Должно быть не менее 3 столбцов, составляющих первичный ключ»? Что это значит? Не могли бы вы дать дальнейшее определение? Или это часть №3?
S.Lott

@ S.Lott PK(NEWID(),NEWID(),NEWID());-)

@pst: Почему это требование? Почему в ПК должно быть три столбца? Почему один или четыре?
S.Lott

Я мог видеть, что ПК с тремя столбцами выглядит как ... LocalID (автоматическое увеличение int), GlobalID (GUID), ForeignId (внешний ключ, например RolesType) и т. Д. LocalID + ForiegnId может быть составной комбинацией клавиш. Guid используется для других веб-сайтов / сервисов. Лично я бы этого не делал, я бы просто использовал Guid + ForiegnId.
Jerad

Ответы:


77

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

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


3
GUID не требуется, просто измените шаг на 10 или 20 или сколько серверов вам понадобится, возможно, для синхронизации в будущем.
Роберт С. Барт,

44
По крайней мере, в 90% случаев GUID не нужен и тратит место.
Джонатан Леффлер,

8
Я серьезно считаю, что GUID - это излишество. Никогда еще не было необходимости иметь GUID в качестве моих первичных ключей.
Cyril Gupta

7
Или, вместо того, чтобы тратить пространство и рисковать конфликтом с GUID, создайте составной ключ из исходного первичного ключа и небольшого идентификатора, где маленький идентификатор отличается для каждого источника синхронизации.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

5
Магазин, в котором я работал, использовал GUID для всего, даже когда были доступны общедоступные идентификаторы, такие как коды страны или языка ISO. И даже когда было CHAR(1)бы достаточно логического или , например, for sex. Излишне говорить, что работать с этим было кошмаром.
Lumi

56

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

Например, в таблице названий и кодов штатов (США) либо имя, либо код могут быть первичным ключом - они составляют два разных ключа-кандидата, и один из них (обычно более короткий - код) выбирается в качестве основной ключ. В теории функциональных зависимостей (и зависимостей соединения - от 1NF до 5NF) решающее значение имеют ключи-кандидаты, а не первичный ключ.

В качестве контрпримера человеческие имена обычно являются плохим выбором в качестве первичного ключа. Есть много людей, которых зовут «Джон Смит» или другими подобными именами; даже с учетом отчества (помните: оно есть не у всех - например, у меня), есть много возможностей для дублирования. Следовательно, люди не используют имена в качестве первичных ключей. Они изобретают искусственные ключи, такие как номер социального страхования (SSN) или номер сотрудника, и используют их для обозначения человека.

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

Поэтому, когда дело доходит до определения первичного ключа данной таблицы, вы должны посмотреть, что эта таблица представляет. Какой набор или наборы значений столбцов в таблице однозначно идентифицируют каждую строку в таблице? Это ключи-кандидаты. Теперь, если каждый ключ-кандидат состоит из 4 или 5 столбцов, вы можете решить, что они слишком неуклюжие для создания хорошего первичного ключа (в первую очередь из-за краткости). В таких случаях вы можете ввести суррогатный ключ - искусственно созданное число. Очень часто (но не всегда) в качестве суррогатного ключа достаточно простого 32-битного целого числа. Затем вы назначаете этот суррогатный ключ первичным ключом.

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

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

В некоторых отношениях это довольно жесткая точка зрения.

У меня нет особых проблем с использованием GUID, когда они нужны, но они, как правило, большие (как в 16-64 байтах), и используются слишком часто. Очень часто достаточно хорошего 4-байтового значения. Использование GUID, где 4-байтового значения будет достаточно, приводит к бесполезной трате дискового пространства и замедляет даже индексированный доступ к данным, поскольку на каждую страницу индекса приходится меньше значений, поэтому индекс будет глубже, и для доступа к Информация.


10
Что касается вашего образца с названиями штатов США, я бы предпочел отдельный суррогатный ключ просто потому, что коды находятся вне вашего контроля. Если они должны измениться по какой-либо причине, у вас возникнут проблемы.
Дирк Фоллмар,

1
(продолжение) Например, Германия заменила 4-значную систему почтовых индексов на 5-значную систему еще в 1990-х годах после повторного объединения.
Дирк Фоллмар,

@divo: Я убежденный сторонник искусственных / суррогатных ключей, но даже я не считаю изменение 4-значного почтового индекса на 5-значное хорошим примером. Почтовые индексы обычно не используются как ключи к чему-либо. (Когда в последний раз вам приходилось запрашивать таблицу PostalCode, чтобы узнать что-нибудь об этом коде? Нет, он почти всегда используется как часть адреса без ссылок в каких-либо других таблицах. Я бы сказал, что ваше предложение почти соответствует использованию суррогатные ключи для самих адресов.)
ErikE 02

@Emtucifor: Да, возможно, ZIP не очень практичный пример, но я хотел сказать, что если часть вашего суррогатного ключа выходит из-под вашего контроля и изменяется по какой-либо причине, у вас проблемы. Подумайте о том, как кто-то создает новую схему номеров социального страхования, новую схему ISSN или, что более реалистично, компанию, решающую создать новую систему идентификаторов продуктов после слияния, присваивая новые номера сотрудников своим сотрудникам для корректировки их роста и т. Д. все это просто вымышленные примеры, но, как показывает мой предыдущий пример с ZIP, иногда устоявшаяся система может измениться.
Дирк Воллмар

2
Ваша первая точка зрения верна. У этого ограничения есть название. Это называется «целостность сущности». EI требует, чтобы каждая сущность имела уникальную идентичность. Первичные ключи часто удовлетворяют этому требованию, за исключением случаев использования автонумерации. С помощью автонумерации вы можете получить две строки, которые идентичны, за исключением автонумерации. Обычно это нарушает целостность объекта.
Уолтер Митти,

26

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

  • Суррогатные ключи полезны, когда никакой другой атрибут или набор атрибутов в таблице не подходит для однозначной идентификации строк.
  • По возможности предпочтительнее использовать естественные ключи, чтобы сделать таблицу более удобочитаемой. Естественные ключи также позволяют внешнему ключу в зависимой таблице содержать реальное значение вместо суррогатного идентификатора. Например, когда вам нужно сохранить state(CA, TX, NY), вы также можете использовать char(2)естественный ключ вместо int.
  • При необходимости используйте составные первичные ключи. Не добавляйте idсуррогатный ключ без надобности, когда существует совершенно хороший составной ключ (это особенно верно в таблицах "многие ко многим"). Обязанность использования ключа из трех столбцов в каждой таблице - абсолютная чепуха.
  • GUID - это решение, когда вам нужно сохранить уникальность на нескольких сайтах. Они также удобны, если вам нужно, чтобы значения в первичном ключе были уникальными, но не упорядоченными или последовательными.
  • INT против BIGINT: нечасто, что таблица требует 64-битного диапазона для первичных ключей, но с увеличением доступности 64-битного оборудования это не должно быть обузой и дает больше уверенности в том, что вы не переполнитесь. INT, конечно, меньше, поэтому при нехватке места это может дать небольшое преимущество.

8
Я не согласен настолько, насколько это возможно. Натуральные ключи ужасны. Что делать, если кто-то хочет изменить данные? О, ты не можешь. Написание соединений на составных естественных ключах - это боль. Переносить этот составной ключ во все связанные таблицы - пустая трата.
Роберт С. Барт

2
@Robert: прочтите о "КАСКАДЕ ОБНОВЛЕНИЙ". Но я понимаю, о чем вы говорите, и согласен, что в большинстве случаев лучше использовать суррогатный ключ, потому что атрибуты могут изменяться и быть неуникальными.
Билл Карвин

2
Первичные ключи должны быть неизменными. В этом случае каскадные обновления - это всего лишь уродливая уловка из-за плохого дизайнерского решения. Естественные ключи НИКОГДА не предпочтительны. То же самое и с составными ключами, которые распространяются как чума. Это знает любой человек, имеющий опыт разработки баз данных более 3 месяцев.
FDCastel 05

7
@FD: Я не согласен с вашим однозначным утверждением, и я разрабатываю базы данных SQL с 1992 года. Но, безусловно, верно, что суррогатные ключи лучше всего могут оставаться неизменными.
Билл Карвин,

20

Мне нравится блог "Программист баз данных" как источник такой информации.

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


2
Они изменили свою ссылку, вот обновленная закладка: database-programmer.blogspot.com/2008/09/…
Брайан Ребейн

Просто унаследовал такой проект. И первое, что они хотели сделать, взорвало схему. Суррогатные ключи FTW. Бизнес-логика в вашей БД FTL.
Джейсон


11

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

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


1
Очень хороший момент - нужно различать ЛОГИЧЕСКУЮ концепцию первичного ключа (может быть допустимо использование GUID для этого, особенно если задействована репликация) и ФИЗИЧЕСКОЙ концепцией ключа кластеризации, которая НИКОГДА не должна быть GUID, поскольку это приводит к чрезмерной фрагментации индекса
marc_s

3
На самом деле это не так. Данные будут вставлены по порядку, что, учитывая случайный характер GUID, может оказаться в любом месте таблицы. Если нет места, произойдет разделение страниц, но уж точно не «переупорядочивание на диске во время каждой вставки», даже близко.
Ральф Шиллингтон,

@ Ральф, ты прав, не КАЖДУЮ вставку, но достаточно, чтобы повысить производительность в 20 раз. sql-server-performance.com/articles/per/…
Портман,

Функция SQL Server newsequentialid () решает проблему фрагментации индекса с помощью идентификаторов GUID (хотя 24 байта все еще немного избыточны, если вам абсолютно не нужна глобальная уникальность). См. Msdn.microsoft.com/en-us/library/ms189786.aspx.
ErikE

10

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

Теперь для выбора суррогатного ключа я придерживаюсь столбцов идентификаторов (я работаю в основном в MS SQL Server). GUID являются слишком большими и Microsoft рекомендует против использования их в качестве ПК. Если у вас несколько серверов, все, что вам нужно сделать, это сделать приращение 10 или 20 или как вы думаете максимальное количество серверов, которое вам когда-либо понадобится для синхронизации / расширения, и просто добавьте начальное число для каждой таблицы на каждом последующем сервере. , и у вас никогда не будет конфликта данных.

Конечно, из-за приращения я делаю столбец идентификаторов BigInt (иначе известный как длинный [64 бита]).

Подсчитав немного, даже если вы сделаете приращение 100, в вашей таблице все равно останется 92 233 720 368 547 758 (> 92 квадриллионов) строк.


9

Я считаю, что использование слова «первичный» во фразе «первичный ключ» в действительности вводит в заблуждение.

Во-первых, используйте определение, что «ключ» - это атрибут или набор атрибутов, которые должны быть уникальными в пределах таблицы,

Затем наличие любого ключа служит нескольким часто несовместимым целям.

  1. Для использования в качестве условий соединения с одной или несколькими записями в дочерних таблицах, которые связаны с этой родительской таблицей. (Явное или неявное определение внешнего ключа в этих дочерних таблицах)
  2. (связанный) Обеспечение того, что дочерние записи должны иметь родительскую запись на родительской вкладке; e (Дочерняя таблица FK должна существовать как Ключ в родительской таблице)
  3. Для увеличения количества запросов, которым необходимо быстро найти определенную запись / строку в таблице.

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

Ясно, что любой бессмысленный, неестественный ключ (например, GUID или автоматически сгенерированное целое число) совершенно не может удовлетворить # 4.

Но часто во многих (большинстве) таблиц совершенно естественный ключ, который может предоставить # 4, часто будет состоять из нескольких атрибутов и быть чрезмерно широким или настолько широким, что его использование для целей # 1, # 2 или # 3 приведет к неприемлемым последствия для производительности.

Ответ прост. Используйте оба. Используйте простой автоматически генерируемый интегральный ключ для всех соединений и FK в других дочерних таблицах, но убедитесь, что каждая таблица, которая требует согласованности данных (очень немногие таблицы не имеют), имеет альтернативный естественный уникальный ключ, который предотвратит вставку несовместимых строк данных. .. Кроме того, если у вас всегда есть и то, и другое, то все возражения против использования естественного ключа (что, если он изменится? Я должен изменить каждое место, где он упоминается как FK), становятся спорными, поскольку вы не используете его для этого. .. Вы используете его только в одной таблице, где это ПК, чтобы избежать противоречивых дублирующих данных ...

Что касается идентификаторов GUID, будьте очень осторожны при их использовании, так как использование идентификаторов в индексе может привести к фрагментации индекса. Наиболее распространенные алгоритмы, используемые для их создания, помещают "случайную" часть guid в наиболее значимые битовые позиции ... Это увеличивает требования к регулярной дефрагментации / переиндексированию индекса по мере добавления новых строк.


Функция SQL Server newsequentialid () решает проблему фрагментации индекса для идентификаторов GUID (хотя 24 байта все еще немного избыточны, если вам абсолютно не нужна глобальная уникальность). См. Msdn.microsoft.com/en-us/library/ms189786.aspx.
ErikE 02

ой, я хотел сказать 16 байт.
ErikE 02

8

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

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

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

Cat1.subcatA.record1
Cat1.subcatA.record2
Cat1.subcatB.record1
Cat2.subcatA.record1

Конечно, первое, что хотели клиенты, - это способ перемещать элементы в дереве. Весь набор софта умер до того, как это произошло.

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


Я полностью согласен. Умные клавиши = тупой.
Роберт С. Барт

2
Это не значит, что естественные клавиши глупы. Но хороший момент.

4

Я поклонник автоинкремента в качестве первичного ключа. В глубине души я знаю, что это отговорка, но с ее помощью так легко сортировать данные по времени их добавления (ORDER BY ID DESC, f'r instance).

3 колонки звучат ужасно жестко для человеческого анализа.

И это компромисс - какая часть реляционных возможностей вам нужна, по сравнению с тем, чтобы ЭТА ТАБЛИЦА СПРАВА была понятна человеку, который ее опрашивает (по сравнению с хранимой процедурой или программным интерфейсом).

автоинкремент для нас, людей. :-(


4

Как правило, это зависит от обстоятельств.

Лично мне нравятся целые числа автоинкремента.

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


3

Должно быть как минимум 3 столбца, составляющие первичный ключ.

Я этого не понимаю.

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

Int / BigInt, автоинкремент которых является достаточно хорошими первичными ключами.

Я предпочитаю Гида. Потенциальная проблема с автоинкрементом заключается в том, что значение (например, «идентификатор заказа») присваивается экземпляром базы данных (например, «базой данных продаж») ... что не будет полностью работать (вместо этого вам понадобятся составные ключи), если вам когда-либо понадобится объединить данные, созданные более чем одним экземпляром базы данных (например, из нескольких офисов продаж, каждый со своей собственной базой данных).


Первичные ключи должны быть уникальными, но не обязательно постоянными. Следовательно, внешние ключи объявлены с помощью «ON UPDATE CASCADE». Но предположение, что первичные ключи постоянны, помогает упростить многие приложения. Это одно из преимуществ суррогатных ключей.
Билл Карвин,

3

RE GUID's

Следите за тем, будет ли это действительно ДЕЙСТВИТЕЛЬНО ДЕЙСТВИТЕЛЬНО большая база данных, большая нагрузка и быстрый доступ.

На моей последней работе, когда у нас были базы данных от 100 до 500 миллионов записей, наши специалисты по базам данных категорически возражали против GUID и в пользу десятичного числа подходящего размера. Они посчитали, что (в Oracle) разница в размере внутренней памяти для строки Guid - против десятичного значения будет иметь очень заметную разницу при поиске. (Большие ключи = более глубокие деревья для пересечения)

Случайный характер идентификаторов GUID также значительно снижает коэффициент заполнения индексных страниц - это резко увеличивает разрыв и дисковый ввод-вывод.


«Уменьшает коэффициент заполнения»? Не уверен, что это может означать. Фактор заполнения - это одноразовая сделка, определяемая как процент свободного пространства, запрошенного на конечном уровне индекса во время его построения. Значения GUID в соответствии с их случайным характером распределения по ширине конечного уровня при вставках в это свободное пространство, предоставленное коэффициентом заполнения.
Ральф Шиллингтон

1
С каких это пор GUID представляет собой строку? Идентификаторы GUID должны храниться внутри как 16 байтов любой уважаемой СУБД. Было бы недопустимо хранить 32 байта в шестнадцатеричном представлении! (или 36 с тире, или 38 с фигурными скобками)
ErikE 02

2

Колонки с автоматическим приращением. Я могу заставить свой код работать без проблем с SQL Server или Oracle, один из которых использует идентификацию, другой - последовательности через мой DAL, и я очень счастлив. Я согласен, GUID иногда необходимы, если вы выполняете репликацию или отправляете данные, чтобы получить их позже после обработки.


2

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

  • Последовательность
  • Независимые от данных (уникальные, не уничтожаются при изменении формата)
  • Человек читаемый

... и нет разумной причины не:

  • Неопределенность в присоединениях? - Таблицы сглаживания - лучшая практика, ИМХО
  • Оптимальные столы? - Удаление одного байта на запись - это преждевременная оптимизация, ИМХО
  • Решение по таблице? - Больше не соответствует
  • Проблемы с масштабированием? - А? Зачем?
  • Иерархическая структура данных? - Это денормализация, совершенно другой предмет религии. Достаточно сказать, что я фанат в некоторых случаях в теории, но никогда на практике :)

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


1

Это классическая «смотря по обстоятельствам». На каждый проект не существует одного правильного ответа. Мне нравятся разные вещи для разных ситуаций. Это зависит от того, использую ли я ORM и что он поддерживает. Это зависит от общей архитектуры (распределенной или нет и т. Д.). Просто выберите тот, который, по вашему мнению, подойдет, и переходите к спорам о табуляциях и пробелах.


Он все еще хочет знать, КАК это зависит; только осознавая это, человек может доверять самому себе в выборе ...
Николас Леонард

1

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

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


1

Я использую только int или GUID с автоинкрементом. В 99% случаев я использую автоинкремент int. Это как раз то, что меня научили использовать, когда я впервые узнал о базах данных, и никогда не сталкивался с причинами, по которым их не использовать (хотя я знаю причины, по которым GUID было бы лучше).

Мне нравится автоматическое увеличение целых чисел, потому что это помогает с удобочитаемостью. Например, я могу сказать: «Взгляните на запись 129383», и кому-то довольно легко зайти и найти ее. С GUID это сделать практически невозможно.


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

1

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

  • Не слишком ли сложное определение первичного ключа? Избегает ли он введения ненужной сложности ради следования «лучшим практикам»?
  • Есть ли лучший возможный первичный ключ, который потребовал бы меньше накладных расходов для обработки базы данных (например, INTEGER против VARCHAR и т. Д.)?
  • Я АБСОЛЮТНО уверен в том, что инвариант уникальности и определенности моего первичного ключа не изменится?

Этот последний, вероятно, привлекает большинство людей к использованию таких вещей, как GUID или самоприращающиеся целочисленные столбцы, потому что полагаясь на такие вещи, как адреса, номера телефонов, имя / фамилия и т. Д., Просто не сокращайте его. Единственный инвариант о людях, о которых я могу думать, - это SSN, но я даже не уверен на 100% в том, что они останутся навсегда уникальными.

Надеюсь, это поможет добавить ясности ...


Есть некоторые исторические случаи, когда SSN не уникальны.
Билл Карвин,

1

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


Означает ли это, что вы «по возможности избегаете автоматического увеличения целых чисел»? Насколько я понимаю, отраслевые эксперты считали, что лучшая производительность в крупномасштабных базах данных достигается за счет индексированных инкрементных PK с минимальной сигнатурой.
Hardryv

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

1

Почти всегда целые числа.

У них есть и другие веские причины, помимо того, что они меньше / быстрее обрабатываются. Что бы вы предпочли записать - «404040» или «3463b5a2-a02b-4fd4-aa0f-1d3c0450026c»?


Последнее может быть целым числом с добавлением тире и основанием 16. Но да, 404040 обрабатывается быстрее, чем длинный GUID. Опять же, 0 обрабатывается еще быстрее, потому что не требует ни единого бита данных!
Strager 01

1

Немного актуально, но кое-что, что я начал делать недавно, когда у меня есть небольшие классификационные таблицы (в основном те, которые будут представлять ENUM в коде), - это то, что я сделаю первичный ключ char (3) или char (4). Затем я делаю эти первичные ключи репрезентативными для значения поиска.

Например, у меня есть система котировок для наших внутренних торговых агентов. У нас есть «Категории затрат», в которых каждой строке котировок назначается одна из ... Итак, у меня есть таблица поиска типов под названием «tCostCategories», где первичный ключ - «MTL», «SVC», «TRV», «TAX», ODC. В других столбцах справочной таблицы хранятся дополнительные сведения, такие как обычные английские значения кодов, «Материал», «Услуги», «Путешествие», «Налоги», «Другие прямые расходы» и т. Д.

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

1 Номер детали $ 40 MTL
2 Другой Номер детали $ 29,99 SVC
3 Номер детали2 $ 150 TRV

Гораздо проще использовать int для представления категорий, а затем связывать 1, 2, 3 во всех строках - у вас есть данные прямо перед вами, и на производительность, похоже, вообще не влияет (не то, что я ' действительно проверен.)

Что касается реального вопроса ... Мне нравятся уникальные идентификаторы RowGUID. Я не на 100% в этом вопросе, но разве все строки не имеют внутреннего RowGuid ?? Если это так, то использование RowGuid на самом деле займет меньше места, чем int (или что-то еще в этом отношении.) Все, что я знаю, это то, что если M $ достаточно для использования в GreatPlains, то для меня этого достаточно. (Я должен пригнуться ??)


1

Еще одна причина, по которой я использую GUID - я использую иерархическую структуру данных. То есть у меня есть таблица «Компания» и таблица «Поставщик», для которых совпадают первичные ключи. Но у меня также есть таблица «Производитель», которая также «наследуется» от компании. Поля, общие для поставщиков и производителей, не отображаются в этих таблицах - они отображаются в компании. В этой настройке использование int намного более болезненно, чем Guids. По крайней мере, вы не можете использовать первичные ключи идентификации.


1
Да, вы можете, вы просто не заставляете таблицы подтипов иметь свойство identity, вместо этого они получают явные вставки значения таблицы супертипов. Пожалуйста , см stackoverflow.com/questions/2112882/...
ErikE

1

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

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

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

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


Опишите несколько примеров надежных естественных ключей?
ErikE 02

1
«Надежный» сам по себе не является свойством ключа. Скорее, это связано с ключом в контексте людей, которые предоставляют данные. Если вы пишете приложение для продажи тому, кто фактически будет управлять данными, вы должны угадать, какие ключи будут надежными для клиента или нет. Учитывая разнообразие клиентов, вы почти наверняка ошибетесь для некоторой части вашей клиентуры.
Уолтер Митти,

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

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

1

Guids.period.

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


обновить, чтобы уточнить мое заявление.

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

При использовании GUID вы можете сгенерировать идентификатор где угодно. Он может быть сгенерирован удаленным сервером, вашим веб-приложением, в самой базе данных или даже в нескольких базах данных в ситуации с несколькими мастерами.

С другой стороны, автоматически увеличиваемый INT может быть безопасно сгенерирован только в первичной базе данных. Опять же, это может быть нормально, если у вас есть приложение, которое будет тесно связано с этим одним резервным сервером БД, и масштабирование - это не то, что вас беспокоит.

Конечно, использование GUID означает, что вам нужно выполнять каждую ночь процессы переиндексации. Однако, если вы используете что-либо, кроме автоматически увеличиваемого INT, вы все равно должны это сделать. Черт возьми, даже с INT в качестве основного, вероятно, у вас есть другие индексы, которые необходимо регенерировать, чтобы справиться с фрагментацией. Следовательно, использование идентификаторов GUID точно не добавляет еще одной проблемы, потому что эти задачи необходимо выполнять независимо.

Если вы посмотрите на более крупные приложения, вы заметите кое-что важное: все они используют GUID в кодировке Base64 в качестве ключей. Причина этого проста: использование идентификаторов GUID позволяет легко масштабировать , тогда как при попытке масштабирования INT может возникнуть множество проблем, через которые нужно прыгнуть.

Наше последнее приложение переживает период тяжелых вставок, который длится около месяца. После этого 90% запросов выбираются для отчетности. Для увеличения емкости я могу подключить дополнительные серверы БД в течение этого большого периода вставки; а позже легко объединить их в единую базу данных для отчетности. Попытка сделать это с помощью INT была бы абсолютным кошмаром.

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


Вы когда-нибудь изучали коэффициент заполнения ваших индексов? Случайный характер приготовления швейцарского сыра GUID резко снижает их эффективность.
stephbu 01

2
"Guids.period": Это так неправильно. При необходимости следует использовать GUID. Как заметил другой комментатор, это может облегчить жизнь программиста, но влияет на общий размер и производительность БД.
Митч Уит

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

3
GUID может подойти для логического первичного ключа, но НИКОГДА НИКОГДА не используйте столбец GUID в качестве ключа CLUSTERING - вы утонете во фрагментации индекса, что приведет к НИЗКОЙ производительности ...
marc_s

Я бы точно не стал объявлять "Guids.period". по этой теме - на самом деле, даже в отрасли, которая настолько переполнена «передовыми практиками», такое утверждение по умолчанию ставит вас на шаткую почву (особенно с этим утверждением). Любая такая болезненная вещь, как GUID, требует серьезного обоснования, и, как говорит JL, я думаю, что большинство из нас сочло бы это крайней мерой. Как будто вы написали, не прочитав остальную часть обсуждения.
Hardryv

0

Это сложная тема, осознавали вы это или нет. Может подпадать под раздел этого FAQ по StackOverflow.

Какие вопросы мне здесь не задавать?

Избегайте вопросов, которые являются субъективными, аргументированными или требуют расширенного обсуждения. Это место для вопросов, на которые можно ответить!

Это обсуждается годами и будет продолжаться годами. Единственные намеки на консенсус, которые я видел, - это то, что ответы в некоторой степени предсказуемы в зависимости от того, спрашиваете ли вы специалиста по объектно-ориентированному программированию (GUID - единственный выход!), Разработчика моделирования данных (естественные ключи - единственный выход!), или ориентированный на производительность администратор базы данных (единственный выход - INT!).


Я не позволю обсуждению затягиваться. Мне просто было любопытно увидеть общий консенсус.
Perpetualcoder

1
Я говорю, задавайте любые вопросы, какие пожелаете! В противном случае это сообщество станет статичным и чрезмерно контролируемым, как, кажется, стала Википедия. Мне кажется, что иногда нужно позволять людям спрашивать все, что они хотят. Доверьтесь им, и они могут поверить в себя!
Николас Леонард
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.