Guid vs INT - Что лучше в качестве первичного ключа?

97

Я читаю вокруг причин использовать или нет Guidи int.

intменьше, быстрее, легко запоминается, сохраняет хронологическую последовательность. И что касается Guid, единственное преимущество, которое я нашел, - то, что это уникально. В каком случае Guidбудет лучше, чем intи почему?

Из того, что я видел, intнет недостатков, кроме как по количественному ограничению, которое во многих случаях не имеет значения.

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

(Guid = UniqueIdentifier) ​​тип в SQL Server

BrunoLM
источник
1
Вместо первичного ключа, я думаю, вы имеете в виду суррогатный ключ, то есть ключ, который не является естественным ключом (последний является ключом, который мы используем в реальном мире). Возможно, вы имеете в виду кластерный индекс.
день
Также помните разницу между (основной) ключ и индекс.
Аллан С. Хансен
1
Также обсуждается на SO: stackoverflow.com/questions/11033435/…
Джон на все руки
2
« intне имеет недостатков, кроме как по количественному ограничению, которое во многих случаях не имеет значения.»: фактически, в этом контексте INT против GUID, верхний предел 32-разрядного со INTзнаком совершенно не имеет значения, учитывая, что верхний предел подписанного 64-разрядный BIGINT- это далеко за пределы практически всех применений (даже более того, если вы начнете нумерацию с нижнего предела; то же самое и для INT), и он по-прежнему вдвое меньше GUID (8 байт вместо 16) и последовательного.
Соломон Руцки

Ответы:

89

Это было задано в переполнении стека здесь и здесь .

Пост Джеффа многое объясняет о плюсах и минусах использования GUID.

GUID Плюсы

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

GUID Минусы

  • Это колоссальное в 4 раза больше, чем традиционное 4-байтовое значение индекса; это может иметь серьезные последствия для производительности и хранения, если вы не будете осторожны
  • Громоздко отлаживать ( where userid='{BAE7DF4-DDF-3RG-5TY3E3RF456AS10}')
  • Сгенерированные GUID должны быть частично последовательными для лучшей производительности (например, newsequentialid()на SQL Server 2005+) и для возможности использования кластерных индексов

Если вы уверены в производительности и не планируете реплицировать или объединять записи, используйте intи установите автоматическое увеличение ( идентификация в SQL Server ).

CoderHawk
источник
20
Еще один минус подхода GUID заключается в том, что вы не можете использовать его в качестве идентификатора для своего конечного пользователя. Вы действительно ожидаете, что ваши пользователи сообщат вам по телефону, что у них есть проблема с заказом "BAE7DF4-DDF-3RG-5TY3E3RF456AS10"? :)
Бранн
3
Если вы не используете последовательные направляющие, а ваш первичный ключ кластеризован (по умолчанию SQL Server), то все ваши вставки данных будут случайно разбросаны по всей таблице, что приведет к массовой фрагментации ваших данных. Это предполагает, что данные обычно вставляются в каком-то порядке, например в хронологическом порядке.
датагод
6
Последовательные инструкции являются последовательными, пока экземпляр SQL не будет перезапущен. Тогда первое значение, скорее всего, будет ниже, чем предыдущее, из-за того, как генерируется корневое значение, что снова вызывает всевозможные проблемы.
Мрденни
20
@Brann В идеале вы бы не передавали свои значения PK конечным пользователям. Я знаю, что это довольно распространенное явление, и это то, что я сам делал в прошлом, прежде чем я научился не делать этого. Но так как это не должно быть сделано, эта конкретная причина предпочитать INT над GUID не является допустимой.
Соломон Руцкий,
2
@ChadKuehn Выбор из- UNIQUEIDENTIFIERза того, INTчто INTимеет верхний предел, является довольно плохой аргументацией, поскольку быть безграничным, хотя и достаточно верным, не является практическим преимуществом. Вы можете легко удвоить эффективную емкость a INT, начав ее с нижнего предела (-2.14 млрд.) Вместо 1. Или, если полных 4,3 млрд. Недостаточно, начните с a, BIGINTкоторый по-прежнему составляет всего 8 байт. по сравнению с 16 для GUID, и это последовательно.
Соломон Руцки
18

Если вы синхронизируете свои данные с внешним источником, постоянный GUID может быть намного лучше. Быстрый пример использования GUID - это инструмент, который отправляется клиенту для сканирования его сети и выполнения определенных классов автоматического обнаружения, сохранения найденных записей, а затем все записи клиентов объединяются в центральную базу данных. назад на нашем конце. Если бы мы использовали целое число, у нас было бы 7398 «1», и было бы намного сложнее отследить, какое «1» было каким.

TML
источник
3
GUID определенно хороши в качестве внешних идентификаторов, и я бы оставил некластеризованный индекс этого значения в качестве «внешнего ключа». Я бы по-прежнему оставил int в качестве «внутреннего ключа», который является основой для отношений кластеризованного индекса и внешнего ключа. Если что-то пересекает архитектурную границу (например, общение с другим приложением), я ценю то, что нельзя перепутать.
Грег
15

Я использовал гибридный подход с успехом. Таблицы содержат ОБА целочисленный idстолбец первичного ключа с автоинкрементом И guidстолбец. guidМожет использоваться по мере необходимости для глобально уникальным образом идентифицировать строку и idможет быть использована для запросов, сортировки и человеческой идентификации ряда.

rmirabelle
источник
3
Какое значение дает GUID, если idуже достаточно, чтобы люди могли идентифицировать строку?
Мартин Смит
6
Идентификатор идентифицирует строку в этой таблице. GUID (по крайней мере, в теории) идентифицирует эту строку в любом месте известной вселенной. В моем проекте мобильные телефоны Android имеют структурно идентичную копию таблицы в локальной базе данных SQLite. Строка и ее GUID генерируются на Android. Затем, когда Android синхронизируется с внутренней базой данных, его локальная строка записывается во внутреннюю таблицу, не опасаясь конфликта со строками, созданными с любого другого мобильного устройства Android.
rmirabelle
2
@MartinSmith Я сам использовал этот подход, и он работает довольно хорошо. GUID - это просто альтернативный ключ с некластеризованным индексом, который передается из приложения, но находится только в первичной таблице. Все связанные таблицы связаны через INTПК. Я нахожу странным, что этот подход не намного более распространен, учитывая, что он является лучшим из обоих миров. Кажется, что большинство людей просто предпочитают решать проблемы в очень абсолютистских терминах, не понимая, что PK не должен быть GUID, чтобы приложение все еще использовало GUID для глобальной уникальности и / или переносимости.
Соломон Руцки
1
@rmirabelle Я думал об этом подходе и колебался, но твой ответ убедил меня. По сути, я нахожусь в ситуации, когда мне нужен уникальный идентификатор для рабочего элемента (который может прийти по сети из любого места), но я не хочу сначала обращаться к базе данных. Идентификаторы GUID являются хорошим решением для этого, но я полагаю, что СОЕДИНЕНИЯ станут намного медленнее, если у меня нет последовательного кластерного ключа.
Пасхальный
1
@easuter Я согласен с тем, что не нужно добавлять поля идентификаторов «просто ради этого», как, например, во многих «мостовых» таблицах «много-ко-многим», где PK должен быть составным из двух связанных между собой FK. Но здесь это не компромисс, так как поле идентификатора не просто ради него. Обеспечение эффективной работы системы довольно важно ;-). И, я бы сказал, что в вашем случае, поскольку GUID генерируются внешне, они не гарантированно уникальны, даже если они прагматично. Но ответственность за целостность данных является достаточной причиной, чтобы GUID был альтернативным ключом, а ID - PK в вашем случае :)
Solomon Rutzky
1

В некоторых передовых практиках все еще упоминается, что вы должны использовать тип данных, который содержит меньше памяти, чем весь набор значений, которые вы собираетесь использовать. Например, если вы используете его для хранения числа работодателей в малом бизнесе и вряд ли получите 100, тогда никто не посоветует использовать значение bigint, тогда как int (даже smallint) подойдет.

Конечно, недостатком этого является «Скажи нет масштабируемости!»


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

Я знаю, что это звучит действительно очевидно, но я вижу, что это часто забывают.

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

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

Спасибо @VahiD за разъяснения.

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

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

golopot
источник
0

Другое дело, как генерируются GUID. mrdenny правильно указал, что даже если используется newsequentialid (), перезапуск экземпляров заставляет новые значения начинаться с «дыр», оставленных в предыдущей обработке. Еще одна вещь, которая влияет на «последовательные» GUID - это сетевая карта. Если я правильно помню, UID NIC используется как часть алгоритма GUID. Если NIC заменяется, нет гарантии, что UID будет иметь более высокое значение, чтобы поддерживать последовательный аспект вещей. Я также не уверен, как несколько сетевых карт могут повлиять на присвоение значений с помощью алгоритма.

Просто мысль, и я надеюсь, что я правильно помню. Хорошего дня!

bobo8734
источник
2
Добро пожаловать в Администраторы базы данных, bobo8734. Не могли бы вы найти источники для этих комментариев? Если вы не уверены в них, возможно, они будут лучше служить комментарием (если у вас есть представитель для этого), чем отдельным ответом.
LowlyDBA
-6

Используйте оба

Используйте int / Bigint для первичного ключа, поскольку его легко поддерживать и использовать в качестве отношений внешнего ключа.

Но свяжите столбец с GUID, чтобы каждая строка также имела уникальный столбец

Абдул Ханнан Иджаз
источник
2
Я уверен, что объяснение ваших аргументов в пользу этого предложения никому не повредит.
Андрей М,
GUID длиной 36 символов будет трудно читать, если вы ищете конкретный случай ..
Абдул Ханнан Иджаз
1
Хорошо, но это на самом деле не объясняет, почему ОП должен использовать оба intи guid, как вы предлагаете в своем ответе. И кроме того, я не говорил об объяснении вашего предложения только мне - я хотел сказать, что вы можете обновить свой ответ . Кстати, вы знаете, что другой ответчик уже предложил то же самое (более или менее), что и вы ?
Андрей М
Да, я имел в виду то же самое .. круто Кстати :)
Абдул Ханнан Иджаз