Таблица в БД для генерации первичных ключей? - PullRequest
7 голосов
/ 12 марта 2010

Вы когда-нибудь использовали отдельную таблицу для "генерации" искусственных первичных ключей для БД (и почему)? Я имею в виду иметь таблицу с двумя столбцами, именем таблицы и текущим идентификатором, с помощью которой вы можете получить новый «идентификатор» для некоторой таблицы, просто заблокировав строку с этим именем таблицы, получив текущее значение ключа, увеличив его по одному и разблокируйте ряд. Почему вы предпочитаете это стандартному столбцу целочисленных идентификаторов?

P.S. «Идея» взята из паттернов Фаулера архитектуры корпоративных приложений, кстати ...

Ответы [ 6 ]

10 голосов
/ 12 марта 2010

Это называется назначением Hi / Lo.

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

Это обычно используется, когда вам приходится иметь дело с несколькими ядрами базы данных. Автоинкрементный идентификатор в Oracle - это последовательность SEQUENCE, которую вы увеличиваете с помощью SEQUENCE.NEXTVALUE из предельного значения INSERT TRIGGER в вашей таблице данных.

Напротив, в SQL Server есть столбцы IDENTITY, которые автоматически автоинкрементируются и управляются самой DBE.

Для того чтобы ваше программное обеспечение работало на обоих DBE, вам необходимо прийти к какому-то стандарту, тогда наиболее распространенным «стандартом», используемым для этого, является назначение Hi / Lo первичному ключу.

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

РЕДАКТИРОВАТЬ # 1

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

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

5 голосов
/ 12 марта 2010

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

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

В этой ситуации может иметь смысл дополнительная таблица для генерации идентификаторов. Однако я бы сделал это немного по-другому. В таблице по-прежнему есть два столбца, но для каждой реальной таблицы создайте одну таблицу «shadow» или «Id mapping». Один из столбцов будет вашим личным идентификатором (уникальным ограничением), а другой - вашим публичным идентификатором (идентификатором может быть значение приращения «7» или «13» или другое число, которое менее очевидно, чем «1»).

Ключевое отличие здесь в том, что вы не хотите делать блокировку самостоятельно. Пусть sql сервер справится с этим.

3 голосов
/ 12 марта 2010

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

Лично я не думаю, что когда-нибудь захочу это сделать. Существует слишком много возможностей для ошибки. Два человека пытаются использовать один и тот же ключ, потому что они забыли заблокировать стол перед захватом идентификатора. Это просто кажется чем-то, что должно быть оставлено на усмотрение СУБД, если это вообще возможно. Как говорил Уилл, эту ситуацию легко минимизировать, но если вы не знаете, что делаете, это может произойти.

2 голосов
/ 12 марта 2010

блокировка строки с этим именем таблицы, получить текущее значение ключа, увеличить его на единицу и разблокировать строка * * тысяча два

Звучит просто, не правда ли?

   UPDATE TableOfId
     SET Id += 1
   OUTPUT Inserted.Id
   WHERE Name = @Name;

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

Чтобы избежать полной сериализации, необходимо получить идентификаторы для отдельных, автономных транзакций, которые могут быть зафиксированы немедленно (обычно неявная транзакция автоматической фиксации в самом UPDATE). Но это сильно усложняет логику приложения. Каждая операция должна поддерживать два отдельных соединения с базой данных: одно для выполнения обычной логики транзакций, а другое для получения необходимых идентификаторов. Даже в этом случае обновление идентификаторов может стать такой горячей точкой, что оно все равно может вызвать видимые конфликты и блокировки (аналогично страшному «счетчику обновлений страниц +1», распространенному в веб-приложениях).

Вкратце: используйте IDENTITY. Генерация идентификаторов оптимизирована для обеспечения высокого параллелизма.

2 голосов
/ 12 марта 2010

Вы бы не предпочли это вообще.

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

1 голос
/ 12 марта 2010

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

...