Совместное использование одной последовательности первичных ключей в базе данных?

14

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

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

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

Edit2: чтобы ответить на вопрос в комментариях, это для Oracle 11g, но мне было интересно на уровне не конкретной базы данных. Если этот вопрос зависит от базы данных, мне было бы интересно узнать, почему, но в таком случае я бы искал ответ, специфичный для Oracle.

Lawtonfogle
источник
2
Обычно это ужасная идея по соображениям производительности.
Philᵀᴹ
1
На самом деле, у каждой таблицы есть свой собственный независимый диапазон первичных ключей. Но только в том, что когда вы смотрите на кучу идентификаторов, вы можете сказать, что это «Аккаунты», «Покупатель» и т. Д. Для этого требуется некоторая настройка и (как любая специальная вещь) постоянный уход и кормление. (Да, я работал с такой системой много лет назад.)
RLF
Какую СУБД вы используете? Oracle? Postgres? DB2?
a_horse_with_no_name
1
Возможно, вы неправильно поняли, что он имел в виду? Может быть, он не был таким буквальным?
Джеймс Райан
Действительно ли администратор компании имел в виду, что в одной из таблиц нет полей первичного ключа?
Макс Вернон,

Ответы:

13

Приемлемо? Конечно. Общие? Нет. Выгодно? Сомнительно.

На моей старой работе мы унаследовали систему, в которой был центральный генератор последовательностей (это была система SQL Server задолго до того, как она SEQUENCEбыла представлена ​​в SQL Server 2012). На самом деле это не было узким местом в производительности и не должно быть, если вы не генерируете сотни тысяч значений в секунду. Но это сделало весь код намного более сложным, чем это должно было быть, без веской причины. Цель проекта состояла в том, чтобы быть уверенным, что если чему-то в системе будет присвоено значение идентификатора 12, то только один элемент в системе может иметь идентификатор 12. Это показалось мне довольно тупым, и я этого никогда не понимал. Если у меня есть клиент с CustomerID = 12, почему это мешает мне иметь заказ с OrderID = 12?

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

Аарон Бертран
источник
Если бы вам пришлось выбирать между чем-то вроде этого и просто использовать уникальные идентификаторы в качестве первичных ключей, у вас было бы предпочтение (хотя ответ, скорее всего, «зависит»)? Похоже, что GUID будет работать вокруг этой проблемы таким же образом, за исключением того, что вы получите стандартную реализацию, вместо того чтобы запускать собственный централизованный генератор первичных ключей. Очевидно, что использование последовательности в SQL 2012 позволит решить обе задачи, но если предположить, что кто-то работает на более старой версии?
SqlRyan
2
@SqlRyan Мне нужно понять, почему OrderID должен полностью отличаться от CustomerID. Я почти наверняка не буду использовать GUID для этого; настройка диапазонов IDENTITY может быть лучше (клиенты начинаются с 1, заказы начинаются с 1000000 и т. д.) с оповещениями, когда вы приблизитесь к исчерпанию диапазона, конечно.
Аарон Бертран
1
@SqlRyan - использование плохо реализованного GUID в качестве кластерного первичного ключа может вызвать все виды проблем. Как сказал Аарон, IDENTITY гораздо лучше подходит для этой цели.
Макс Вернон,
В предыдущей системе, которую я видел, использовалась одна последовательность по всей базе данных, это было сделано для того, чтобы внешний ключ мог указывать на множество разных таблиц вместо одной таблицы, так что, когда вы сказали, что внешний ключ двух разных строк было 12, вы знали, что они указывали на одно и то же, не проверяя, на какую возможную таблицу они указывали. 13 в том же столбце потенциально может быть первичным ключом в другой таблице. Мне лично очень не нравится этот стиль дизайна.
Lawtonfogle
@AaronBertrand Или, в качестве альтернативы, используйте простые целочисленные идентификаторы и добавляйте некоторый код в начало, когда они обращены к клиенту. например. I1337, C1337 явно счет или клиент
JamesRyan
7

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

Мы решили использовать последовательные идентификаторы GUID в качестве наших первичных ключей, чтобы избежать некоторых ошибок фрагментации индекса GUID. К сожалению, они довольно большие.

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

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

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

Я уверен, что мы избежали многих ошибок в нашем приложении в результате их использования.

RayG
источник
4

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

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

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

mustaccio
источник
2
Возможно, вы захотите добавить подробности о том, как создается узкое место и почему это плохая идея.
Макс Вернон,
2

Целью PrimaryKey в таблицах базы данных является прежде всего обеспечение уникальности данных, которые должны быть уникальными, поскольку все рабочие процессы не могут быть охвачены и гарантированы, что это не приведет к дублированию данных. Вторая причина заключается в том, что много раз PK также является основным кандидатом для кластеризованного индекса в таблице, поэтому он также ускоряет поиск данных, когда / где эти столбцы правильно используются в запросе выбора.

использование порядкового номера в качестве первичного ключа такое же, как в каждой таблице есть столбец Identity, и в PrimaryKey используется только этот столбец. наличие единого порядкового номера в базе данных должно иметь определенное использование, но с точки зрения PrimaryKey я не понимаю причину. например, в одном из проектов Datawarehouse, над которым я работал, у нас есть столбец с именем LoadBatchID, и из ETL для отчетов 50% всей таблицы имеет этот столбец, но в некоторых местах он имеет другое значение. мы использовали уникальный процесс в качестве генератора чисел, чтобы убедиться, что мы не находим конфликты, а также помогли нам проследить до исходного файла, откуда поступили данные и что происходит на разных этапах ETL.

Ануп Шах
источник
2

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

create table god_entity (
  id bigserial primary key
);

create table some_table (
  id bigint primary key references god_entity(id),
  ...
);

create table some_other_table (
  id bigint primary key references god_entity(id),
  ...
);

create table comment (
  id bigint primary key references god_entity(id),
  ...
);

create table entity_comment (
  entity_id bigint not null references god_entity(id),
  comment_id bigint not null references god_entity(id),

  primary key (entity_id, comment_id)
);

Обычно это не сделано. ,

Не знаю о характеристиках производительности.

Нил Макгиган
источник