Guid vs INT - Що краще в якості основного ключа?


97

Я читав про причини вживання чи ні Guidта int.

intменший, швидший, легкий для запам'ятовування, зберігає хронологічну послідовність. А щодо Guidєдиної переваги, яку я знайшов - це унікальність. У якому випадку а Guidбуде кращим, ніж intі чому?

У тому, що я бачив, intнемає жодних недоліків, окрім обмеження кількості, які у багатьох випадках не мають значення.

Чому саме Guidстворено? Насправді я думаю, що вона має інше призначення, а не служити основним ключем простої таблиці. (Будь-який приклад реальної програми, яка використовує Guidдля чогось?)

(Guid = UniqueIdentifier) ​​введіть на SQL Server


1
Замість первинного ключа, я думаю, ви маєте на увазі сурогатний ключ, тобто ключ, який не є природним ключем (останній - це ключ, який ми використовуємо в реальному світі). Можливо, ви маєте на увазі кластерний індекс.
одного дня, коли

Також пам’ятайте про різницю між (Первинним) KEY та INDEX.
Аллан С. Хансен

1
Також обговорювались на SO: stackoverflow.com/questions/11033435/…
Іон усіх торгів

2
" intне має жодних недоліків, за винятком обмеження кількості, яке в багатьох випадках не має значення.": насправді в цьому контексті INT проти GUID верхня межа підписаного 32-бітного INTзовсім не має значення, враховуючи, що верхня межа підписаного , 64-розрядна BIGINTзначно перевищує майже всі види використання (тим більше, якщо ви починаєте нумерацію з нижньої межі; і те саме стосується INT), і вона все ще наполовину менше GUID (8 байт замість 16) та послідовних.
Соломон Руцький

Відповіді:


89

Про це запитували в Стек Overflow тут і тут .

Повідомлення Джеффа багато пояснює плюси та мінуси використання GUID.

Плюси GUID

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

Мінуси GUID

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

Якщо ви впевнені в продуктивності і не плануєте копіювати або об'єднувати записи, то використовуйте intта встановіть його автоматичне збільшення ( насіння ідентифікаторів у SQL Server ).


20
Інший підхід підходу GUID полягає в тому, що ви не можете використовувати його як ідентифікатор для свого кінцевого користувача. Ви дійсно очікуєте, що ваші користувачі скажуть вам по телефону, що у них є проблема із замовленням "BAE7DF4-DDF-3RG-5TY3E3RF456AS10"? :)
Brann

3
Якщо ви не використовуєте послідовних посібників, а ваш основний ключ кластеризований (за замовчуванням SQL Server), всі ваші вставки даних будуть випадково розкидані по всій таблиці, що призведе до масової фрагментації ваших даних. Це припущення, що дані зазвичай вставлятимуться у певному порядку, наприклад, у хронологічному.
datagod

6
Послідовні посібники мають лише послідовний характер, доки екземпляр SQL не буде перезапущений. Тоді перше значення буде, швидше за все, нижчим за попереднє через спосіб генерування кореневого значення, викликаючи всілякі проблеми знову.
mrdenny

20
@Brann В ідеалі в першу чергу вам не надаватимуть ваші ПК значення кінцевим користувачам. Я знаю, що це є дещо звичайним, і це я щось робив у минулому, перш ніж я навчився цього не робити. Але оскільки цього робити не слід, саме ця причина віддати перевагу INT перед GUID не є дійсною.
Соломон Руцький

2
@ChadKuehn Вибір UNIQUEIDENTIFIERчерез те, INTщо INTмає верхню межу, є доволі поганим обґрунтуванням, оскільки безмежний, хоча і правдивий, не є корисною практикою . Ви можете легко подвоїти ефективну потужність INTA, запустивши її на нижній межі (-2,14 млрд) замість 1. Або, якщо повних 4,3 мільярдів недостатньо, тоді почніть з того, BIGINTщо досі становить лише 8 байт порівняно з 16 для GUID, і він є послідовним.
Соломон Руцький

18

Якщо ви синхронізуєте свої дані із зовнішнім джерелом, стійкий GUID може бути набагато кращим. Швидкий приклад того, як ми використовуємо GUID - це інструмент, який надсилається замовнику для сканування їх мережі та виконання певних класів автовідкриття, зберігання знайдених записів, а потім усі записи клієнтів інтегруються в центральну базу даних назад на нашому кінці. Якби ми використовували ціле число, у нас було б 3498 "1" s, і було б набагато складніше відстежувати, який "1" був.


3
GUID, безумовно, хороші як зовнішні ідентифікатори, і я б зберігав некластеризований індекс цього як "зовнішній ключ", я все одно зберігав би int як "внутрішній ключ", який є основою для кластерного індексу та зв'язків зовнішніх ключів. Якщо щось перетинає архітектурну межу (наприклад, спілкування з іншим додатком), я ціную те, що щось не можна змішати.
Грег

15

Я успішно використовував гібридний підхід. Таблиці містять НАЗАД цілий цілий idстовпець первинного ключа з автоматичним збільшенням та guidстовпець Баночки guidможуть використовуватися у міру необхідності для глобальної однозначної ідентифікації рядка і idможуть використовуватися для запитів, сортування та ідентифікації людини рядка.


3
Яке значення надає GUID, якщо idвже достатньо, щоб люди могли визначити ряд?
Мартін Сміт

6
Ідентифікатор ідентифікує рядок у цій таблиці. GUID (принаймні теоретично) визначає цей рядок у будь-якій точці відомого Всесвіту. У моєму проекті мобільні телефони Android мають структурно ідентичну копію таблиці в локальній базі даних SQLite. Рядок та його GUID створюються на Android. Потім, коли Android синхронізується з базовою базою даних, його локальний рядок записується в задню таблицю, не боячись конфліктувати з рядками, створеними з будь-якого іншого мобільного Android.
rmirabelle

2
@MartinSmith Я сам використовував такий підхід, і він працює досить непогано. GUID - це лише альтернативний ключ із індексом NonClustered і передається з програми, але знаходиться лише в первинній таблиці. Усі пов'язані таблиці пов'язані через INTПК. Мені здається дивним, що такий підхід не є набагато поширенішим, враховуючи, що він найкращий для обох світів. Схоже, більшість людей просто вважають за краще вирішувати проблеми в абсолютно абсолютистському розумінні, не розуміючи, що ПК не потребує GUID для того, щоб додаток все ще використовував GUID для глобальної унікальності та / або портативності.
Соломон Руцький

1
@rmirabelle Я думав над цим підходом і вагався, але твоя відповідь переконала мене. В основному я знаходжусь у ситуації, коли мені потрібно мати унікальний ідентифікатор для робочого елемента (який може надходити по мережі з будь-якого місця), але я не хочу спочатку переходити до бази даних. GUID - це гарне рішення для цього, але я думаю, що ПРИЄДНАННЯ стануть набагато повільніше, якщо у мене немає послідовного кластерного ключа.
східний

1
@easuter Я погоджуюся з тим, щоб не додавати поля ідентифікаторів "просто заради цього", наприклад, у "багато-багато" таблиць "міст", де ПК повинен бути складовою двох FK-файлів, які пов'язані між собою. Але це не є компромісом, оскільки поле ID не просто заради нього. Дозвіл ефективної роботи системи є досить важливим ;-). І я заперечую, що у вашому випадку, оскільки GUID створюються зовні, вони не гарантуються унікальними, навіть якщо вони прагматично є. Але відповідальність за цілісність даних є достатньою підставою для того, щоб GUID був альтернативним ключем, а ідентифікатор був ПК у вашому випадку :)
Соломон Руцький

1

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

Звичайно, недолік цього схожий на "Скажи ні масштабуванню!"


Також я знаю, що це не зовсім пов'язано, але є ще один фактор щодо цього. Якщо це не надмірно, я зазвичай намагаюся рекомендувати використовувати первинний ключ, що не генерується, якщо це має сенс. Наприклад, якщо ви зберігаєте інформацію про драйвера, не переймайтеся, створюючи новий стовпчик з автоматичною генерацією для "ID", просто використовуйте номер ліцензії.

Я знаю, що це звучить дійсно очевидно, але я бачу, що його забувають досить часто.

Для контексту: ця частина відповіді була адресована теоретичним підходом даних, де ви хочете, щоб ваш ПК був унікальним ідентифікатором даних для запису. У більшості випадків ми створюємо ті, коли вони вже існують, звідси і попередня відповідь.

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

Дякую @VahiD за роз'яснення.


використання значущих первинних ключів взагалі не рекомендується. Розгляньте нижче сценарій, хтось ввів неправильний номер ліцензії, і ви використовували цей ідентифікатор у 3-4 таблицях як іноземний ключ, як виправити цю помилку? просто редагування номера ліцензії в цьому випадку може бути недостатньо.
VahiD

1
Смішно: Я прочитав ваш коментар і подумав "так, звичайно", потім повернувся, щоб прочитати свою відповідь і подумав "я це сказав"? Смішно, як все змінюється за пару років. Я, ймовірно, виходив з більш теоретичного походження, але якщо ви не маєте жорсткого контролю над ним (рідко), це не приносить великої користі. Я оновлю відповідь.
Альфа

вклад в розвиток :)
VahiD

1

Використання ідентифікаторів автоматичного збільшення може витікати інформацію про вашу ділову діяльність. Якщо ви керуєте магазином і використовуєте order_idдля публічного визначення покупки, будь-хто може дізнатись вашу кількість продажів на місяць за допомогою простої арифметики.


0

Інша справа з тим, як генеруються GUID. mrdenny правильно вказав, що навіть якщо використовується newsequentialid (), перезапуск екземплярів призводить до появи нових значень із «дірок», залишених у попередній обробці. Ще одна річ, яка впливає на "послідовні" GUID, - це мережна карта. Якщо я добре пам’ятаю, UID NIC використовується як частина алгоритму GUID. Якщо NIC буде замінено, немає гарантії, що UID буде вищим значенням для підтримки послідовного аспекту. Я також не впевнений, як кілька NIC можуть впливати на призначення значень за допомогою алгоритму.

Просто думка, і я сподіваюся, що пам’ятаю правильно. Хорошого дня!


2
Ласкаво просимо до адміністраторів баз даних, bobo8734. Не могли б ви знайти джерела для цих коментарів? Якщо ви не впевнені в них, можливо, вони будуть краще слугувати коментарем (коли у вас є представник), ніж окремою відповіддю.
LowlyDBA

-6

Використовуйте обидва

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

Але прив’яжіть стовпчик до GUID, щоб кожен рядок також мав унікальний стовпець


2
Пояснення своїх міркувань щодо цієї пропозиції нікому не зашкодить, я впевнений.
Андрій М

GUID довжиною 36 символів буде важко прочитати, якщо ви шукаєте конкретний випадок ..
Abdul Hannan Ijaz

1
Гаразд, але це насправді не пояснює, чому ОП повинні використовувати і те, intі guidяк ви пропонуєте у своїй відповіді. А крім того, я не говорив про те, щоб пояснити мені вашу пропозицію лише мені - я вважав, що ви можете оновити свою відповідь . До речі, чи знаєте ви, що інший відповідач вже запропонував те саме (більш-менш), як і ви ?
Андрій М

Так, я мав на увазі те саме. Класно BTW :)
Абдул Ханнан Іяз
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.