Последовательный GUID или bigint для «огромной» таблицы базы данных PK

14

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

У меня огромная база данных - она ​​увеличивается примерно на 10 000 000 записей в день. Данные являются реляционными, и по соображениям производительности я загружаю таблицу с BULK COPY. По этой причине мне нужно генерировать ключи для строк, и я не могу полагаться на столбец IDENTITY.

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

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

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

Barguast
источник
2
Как бы вы сгенерировали «последовательный GUID»?
Это пользовательская реализация. Это в основном формат типа GUID, в котором 6 байтов заменены байтами метки времени, а 2 байта представляют порядковый номер, где метка времени одинакова. Не гарантируется получение идеальных последовательных значений, но этого достаточно, чтобы фрагментация индекса не стала для меня проблемой.
Поэтому вы загружаете эти данные из разных источников? Я также предполагаю, что индекс, который вы беспокоитесь о фрагментации является кластеризованным индексом?
2
Если вы собираетесь использовать последовательный GUID, вы должны посмотреть на NEWSEQUENTIALID (). Он должен делать то, что вы хотите (монотонно увеличивается), и не полагаться на пользовательский код.
2
Посмотрите на пост Джеремии Пешки "Проблемы с ключами". Хорошо прочитал, и он много раз сталкивался с этой реализацией.
billinkc

Ответы:

4

Я в похожей ситуации. В настоящее время я использую последовательный подход GUID и не имею фрагментации и легкой генерации ключей.

Я заметил два недостатка, которые заставили меня начать переход на bigint:

  1. Использование пространства . 8 байт на индекс. Умножьте это на 10 индексов или около того, и вы получите огромную трату пространства.
  2. Индексы Columnstore не поддерживают идентификаторы GUID.

(2) Был убийцей для меня.

Теперь я сгенерирую свои ключи так:

yyMMddHH1234567890

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

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

Надеюсь, что некоторые из них переносятся в вашу ситуацию Я определенно рекомендую использовать bigint.

USR
источник
1
Отмечая это как «ответ», так как он лучше всего подходит (и вы, похоже, понимаете, что я спрашиваю, и почему это не так просто, как может показаться на первый взгляд). Я думаю, что я собираюсь пойти с генератором общей последовательности (который будет работать аналогично вашему предложению алгоритма HiLo). У меня это работает на другой системе с небольшим количеством проблем, мне просто придется мириться с дополнительной зависимостью. Ну что ж. Благодарю.
Barguast
3

С типом INT, начинающимся с 1, вы получаете более 2 миллиардов возможных строк - этого должно быть более чем достаточно для подавляющего большинства случаев. При этом BIGINTвы получите примерно 922 квадриллиона (922 с 15 нулями - 922 000 миллиардов) - вам достаточно ??

Если вы INT IDENTITYначинаете с 1 и вставляете строку каждую секунду, вам нужно 66,5 лет, прежде чем вы достигнете предела в 2 миллиарда ....

Если вы BIGINT IDENTITYначинаете с 1 и вставляете тысячу строк каждую секунду, вам нужно ошеломить 292 миллиона лет, прежде чем вы достигнете предела в 922 квадриллиона ....

Используя ваши 10 миллионов строк в день, у вас будет достаточно данных примерно для 1 844 667 407 380 дней ( 1844 миллиарда дней или 5 миллиардов лет ) - этого достаточно для ваших нужд. ?

Подробнее об этом (со всеми имеющимися опциями) читайте в MSDN Books Online .

marc_s
источник
1
Скорость ввода 10 миллионов строк в день исчерпала бы диапазон INT за 200 дней.
Македа
@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, с такими параметрами, как cache / nocache, вы также можете назначить диапазон последовательности для вашей пакетной операции как sp_sequence_get_range.


источник
К сожалению, SEQUENCE не поддерживается в Sql Azure.
Тимоти Ли Рассел
2

Является ли причиной того, что вы не можете использовать IDENTITY, потому что между загружаемыми таблицами уже есть связи по внешнему ключу? И нет ли другого естественного ключа для вас, чтобы иметь возможность связать их в операции от промежуточного участка до производственного участка? По этой причине я хотел бы узнать немного больше о том, как они в настоящее время «связаны» в исходной системе, перед тем, как приступить к массовому копированию? Много ли исходные системы просто используют свои собственные последовательности и имеют возможность конфликтующих последовательностей при переносе в общую базу данных?

Мне знакома техника COMB ID / последовательный GUID, и она работоспособна в любое время, когда вам эффективно требуется глобальная уникальность, назначенная вне базы данных - это эффективно используемая идентификация строк как внутри, так и вне базы данных. По этой причине в сильно распределенных средах или отключенных сценариях это хороший выбор.

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

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

Кейд Ру
источник
0

В общем случае можно использовать OUTPUTпункт INSERTкоманды, чтобы данные вставлялись в обе таблицы и были связаны с полем идентификации.

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

Serg
источник