2015-04-29 3 views
0

Я хочу создать пользовательский столбец идентификации, относящийся к типу продукта. Может ли этот запрос гарантировать порядок идентификации и разрешить параллелизм. Это пример запроса:Столбец пользовательской идентификации SQL Server

 
BEGIN TRAN 

INSERT INTO TBLKEY 
VALUES((SELECT 'A-' + CAST(MAX(CAST(ID AS INT)) + 1 AS NVARCHAR) FROM TBLKEY),'EHSAN') 

COMMIT 
+0

вместо +1 пытаются использовать последовательность. –

+0

@DudiKonfino, я не могу использовать идентификатор или последовательность и вычисленное поле, потому что непрерывное число связано с типом продукта, например, это 10001 productA, 20001 productB – Ehsan

+0

Вы можете создать с начала с 10001 и шаг 10000 –

ответ

0

Попробуйте это:

BEGIN TRAN 

INSERT INTO TBLKEY 
VALUES((SELECT MAX(ID) + 1 AS NVARCHAR) FROM TBLKEY WITH (UPDLOCK)),'EHSAN') 

COMMIT 

При выборе максимального идентификатора вы получаете блокировку U на строку. Блокировка U несовместима с блокировкой U, которая будет пытаться получить другой сеанс с тем же запросом, который выполняется одновременно. Только один запрос будет выполнен в данный момент времени. Иды будут в порядке и непрерывны без каких-либо промежутков между ними.

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

Вы можете понять разницу, выполнив следующие действия:

Подготовьте таблицу

CREATE TABLE T(id int not null PRIMARY KEY CLUSTERED) 
INSERT INTO T VALUES(1) 

И затем выполнить следующий запрос в двух различных сеансов один за другим с менее чем 10 секунд друг от друга

BEGIN TRAN 
DECLARE @idv int 
SELECT @idv = max (id) FROM T 
WAITFOR DELAY '0:0:10' 
INSERT INTO T VALUES(@idv+1) 
COMMIT 

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

Теперь сделайте то же самое с помощью следующего запроса

BEGIN TRAN 
DECLARE @idv int 
SELECT @idv = max (id) FROM T WITH (UPDLOCK) 
WAITFOR DELAY '0:0:5' 
INSERT INTO T VALUES(@idv+1) 
COMMIT 

просмотреть содержимое T

Cleanup Т Стол с DROP TABLE T

+0

спасибо, я тестировал только оператор Select, как вы говорите, в двух разных транзакциях и работал отлично. – Ehsan

+0

Возможно, это будет работать и без UPDLOCK, но это будет неправильно. – Blim

+0

с UPDLOCK также я могу поместить новый id в переменную и использовать это в инструкции Insert: 'BEGIN TRAN DECLARE @NEWID AS NVARCHAR SET @NEWID = (SELECT MAX (ID) + 1 AS NVARCHAR) FROM TBLKEY WITH (UPDLOCK)) INSERT INTO TBLKEY VALUES (@ NEWID, 'EHSAN') COMMIT' это правильно? – Ehsan

0

Это было бы плохо, что нужно сделать, так как не существует способа, чтобы гарантировать, что два запроса, работающие в то же время не получит MAX (ID) как то же самое значение ,

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

Ed

+0

Он мог сделать свою попытку, если он изменил запрос на FROM TBLKEY WITH (UPDLOCK). Таким образом, два запроса, запущенные одновременно, не могут получить один и тот же MAX (ID), один из которых будет заблокирован другим. Кроме того, я думаю, что произведенные идентификаторы будут не только в порядке возрастания, но и будут непрерывными. Недостатком этого способа является то, что все параллельные запросы сериализуются. – Blim

+0

Не говоря уже о том, что CAST (ID AS INT) имеет форму CAST («A-XXXX»), которая потерпит неудачу. – Blim

+0

@ Ed Elliot, я не могу использовать идентификатор и вычисленное поле, потому что непрерывное число связано с типом продукта, например, 10001 productA, 20001 productB. – Ehsan

Смежные вопросы