Послідовний GUID або bigint для 'величезної' таблиці бази даних ПК


14

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

У мене величезна база даних - вона зростає приблизно на 10 000 000 записів на день. Дані є реляційними, і з міркувань продуктивності я завантажую таблицю BULK COPY. З цієї причини мені потрібно генерувати ключі для рядків, і я не можу покластися на стовпець ІДЕНТИЧНОСТІ.

64-розрядне ціле число - bigint - достатньо широке для мене використання, але для того, щоб гарантувати унікальність, мені потрібен централізований генератор, який би зробив для мене свої ідентифікатори. В даний час у мене є така служба генератора, яка дозволяє сервісу резервувати X послідовних номерів і не гарантує зіткнень. Однак наслідком цього є те, що всі сервіси, які я маю, покладаються на цей один централізований генератор, і тому я обмежений у тому, як я можу розповсюджувати свою систему, і я не радий, що інші залежності (наприклад, що вимагають доступу до мережі), накладені за цією конструкцією. Це було певною проблемою.

Зараз я розглядаю можливість використання послідовних GUID в якості моїх первинних ключів (згенерованих зовні до SQL). Наскільки мені вдалося переконатися в моєму власному тестуванні, єдиним недоліком цього є дисковий простір більш широкого типу даних (який посилюється при їх використанні в індексах). Я не був свідком помітного уповільнення виконання запитів порівняно з альтернативою bigint. Завантаження таблиці за допомогою BULK COPY відбувається трохи повільніше, але не набагато. Мої індекси на основі GUID не стають фрагментарними завдяки моїй послідовній реалізації GUID.

В основному, я хочу знати, якщо є якісь інші міркування, які я, можливо, не помітив. На даний момент я схильний скочити і почати використовувати GUID. Я ні в якому разі не експерт по базі даних, тому дуже вдячний за будь-які вказівки.


2
Як би ви створили "послідовний GUID"?

Це спеціальна реалізація. Це в основному формат типу GUID, який має 6 байт, замінених байтами часових позначок, і 2 байти, який представляє порядковий номер, де часова марка однакова. Це не гарантує отримання ідеальних послідовних значень, але це досить добре, щоб зробити фрагментацію індексу для мене проблемою.

Ви завантажуєте ці дані з різних джерел? Я також припускаю, що індекс, який ви переживаєте за фрагментацію, - це кластерний індекс?

2
Якщо ви збираєтесь із послідовним GUID, слід переглянути NEWSEQUENTIALID (). Він повинен робити те, що ви хочете (монотонно зростаючи), а не покладатися на спеціальний код.

2
Подивіться на пост Єремії Пешка на тему Проблеми з клавішами Добре читайте, і він багато разів займався цим впровадженням.
billinkc

Відповіді:


4

Я в подібній ситуації. В даний час я використовую послідовний підхід GUID і не маю фрагментації та простого створення ключів.

Я помітив два недоліки, які змусили мене почати мігрувати до bigint:

  1. Використання місця . 8 байт більше на індекс. Помножте це на 10 індексів або близько того, і ви отримаєте величезну витрату місця.
  2. Індекси стовпців стовпців не підтримують GUID.

(2) Був вбивцею для мене.

Зараз я буду генерувати свої ключі так:

yyMMddHH1234567890

Я буду використовувати провідну дату плюс годину і матиме послідовну частину після цього. Це дозволяє мені запитувати мої дані за датою без будь-якого індексу додавання. Це приємний бонус для мене.

Я буду генерувати послідовну частину bigint за допомогою алгоритму HiLo , який добре піддається розповсюдженню .

Сподіваємось, що щось із цього перенесеться у вашу ситуацію. Я напевно рекомендую використовувати bigint.


1
Позначте це як "відповідь", оскільки це найкраще підходить (і ви, здається, цінуєте те, що я прошу, і чому це не так просто, як це може здатися вперше). Я думаю, що я збираюся перейти з спільним генератором послідовностей (який буде працювати аналогічно вашим пропозиціям алгоритму HiLo). У мене це працює в іншій системі з мало проблемами, мені просто доведеться миритися з додатковою залежністю. Що ж, добре. Спасибі.
Баргуаст

3

З типом INT, починаючи з 1, ви отримуєте понад 2 мільярди можливих рядків - це має бути більш ніж достатньо для переважної більшості випадків. З BIGINT, ви отримуєте приблизно 922 квадрильйони (922 з 15 нулями - 922'000 мільярдів) - вам достатньо ??

Якщо ви використовуєте INT IDENTITYстарт на 1, і ви вставляєте рядок щосекунди, вам потрібно 66,5 років, перш ніж ви досягнете межі в 2 мільярди ....

Якщо ви використовуєте BIGINT IDENTITYстарт на 1, і ви вставляєте тисячу рядків щосекунди, вам потрібні приголомшливі 292 мільйони років, перш ніж ви потрапите на межу 922 квадрильйонів ....

Використовуючи ваші 10 мільйонів рядків на день, це забере у вас достатня кількість приблизно 1'844'674'407'370 днів ( 1844 мільярдів днів або галочка за 5 мільярдів років ) - це досить добре для ваших потреб ?

Детальніше про це (з усіма можливими варіантами) читайте в Книгах MSDN Online .


1
Швидкість введення 10 мільйонів рядків на день може вичерпати діапазон INT за 200 днів.
mceda

@mceda: так - я щось інше вимагав? Це не вичерпує BIGINTдіапазон так швидко, хоча ....
marc_s

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

2
@Barguast: чи не могли ви просто масово вставити ваші дані в таблицю інспекції (без посвідчення особи), а потім перемістити їх звідти у ваші фактичні таблиці даних за допомогою BIGINT IDENTITY?
marc_s

@marc_s: так, наданий розрахунок не узгоджувався з питанням: "Якщо ви використовуєте INT IDENTITY, починаючи з 1, і ви вставляєте рядок щосекунди, вам потрібно 66,5 років, перш ніж ви досягнете межі в 2 мільярди".
mceda

2

Рекомендую використовувати SEQUENCE типу даних BIGINT у SQL 2012. Це набагато гнучкіше, ніж IDENTITY, з такими параметрами, як кеш / нокеш, ви також можете призначити діапазон послідовностей для вашої пакетної операції як sp_sequence_get_range.


На жаль, SEQUENCE не підтримується на Sql Azure.
Тімоті Лі Рассел

2

Ви не можете використовувати IDENTITY, оскільки між окремими таблицями, які ви завантажуєте, вже існують зовнішні ключові зв’язки? І немає іншого природного ключа для того, щоб ви могли зв'язати їх під час операції від місця постановки до виробничої зони? З цієї причини я хотів би дізнатися трохи більше про те, як вони в даний час "пов'язані" у вихідній системі, перш ніж об'ємна копія? Чи використовують декілька вихідних систем просто власні послідовності та чи є можливість конфліктувати послідовності, коли вони вводяться у спільну базу даних?

Метод COMB ID / послідовний GUID - це той, з ким я знайомий, і він працює, коли вам ефективно потрібна глобальна унікальність, присвоєна поза базою даних, - це фактично корисна ідентифікація рядків як всередині, так і зовні бази даних. З цієї причини, у високорозподілених середовищах або роз'єднаних сценаріях це правильний вибір

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

Крім того, якщо розподілено покоління, якщо рядки насправді не входять у колонку GUID, проблеми з використанням цього для кластеризованого індексного ключа (вузький, статичний, зростаючий) потенційно можуть спричинити деяку фрагментацію порівняно з кластеризацією на ІДЕНТИТЕТІ залишаються.


0

Взагалі можна використовувати OUTPUTпункт INSERTкоманди, щоб дані були вставлені в обидві таблиці та пов'язані з полем ідентичності.

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

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