Таблица в DB для генерации первичных ключей?

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

P.S. "идея" от Шаблонов Fowlers Архитектуры приложений для предприятия, btw...

7
задан Gordon 17 February 2012 в 15:17
поделиться

6 ответов

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

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

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

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

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

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

EDIT #1

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

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

10
ответ дан 6 December 2019 в 07:50
поделиться

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

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

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

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

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

Короче: используйте ИДЕНТИЧНОСТЬ. Генерация удостоверений оптимизирована для высокой степени параллелизма.

2
ответ дан 6 December 2019 в 07:50
поделиться

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

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

2
ответ дан 6 December 2019 в 07:50
поделиться

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

1
ответ дан 6 December 2019 в 07:50
поделиться

Всякий раз, когда вы можете использовать возможности sql server's identity или guid, вы должны это делать. Однако есть несколько ситуаций, когда это может оказаться невозможным.

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

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

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

5
ответ дан 6 December 2019 в 07:50
поделиться

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

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

3
ответ дан 6 December 2019 в 07:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: