Може да получите неправилни стойности, когато използвате SCOPE_IDENTITY() и @@IDENTITY

Симптоми

Когато използвате функции SCOPE_IDENTITY() или @@IDENTITY за извличане на стойностите, вмъкнати в колона за самоличност, е възможно да забележите, че тези функции понякога връщат неправилни стойности. Проблемът възниква само когато вашите заявки използват паралелни планове за изпълнение.

Причина

Microsoft потвърждава, че това е проблем в продуктите на Microsoft, които са изброени в началото на тази статия.

Решение

Кумулативна информация за актуализацията

SQL Server 2008 R2 Service Pack 1

Корекцията за този проблем е издадена за първи път в сборна актуализация 5 за SQL Server 2008 R2 Service Pack 1. За допълнителна информация как да получите този пакет за кумулативна актуализация, щракнете върху следния номер на статия, за да прегледате статията в базата знания на Microsoft:

2659694 Сборен пакет за актуализация 5 за SQL Server 2008 R2 Service Pack 1

Забележка Тъй като компилациите са кумулативни, всяка нова корекция съдържа всички актуални поправки и корекции на защитата, които са били включени в предишното издание на корекция на SQL Server 2008 R2. Препоръчваме ви да помислите за прилагане на най-новото издание на корекцията, което съдържа тази гореща корекция. За допълнителна информация щракнете върху следния номер на статия, за да прегледате статията в базата знания на Microsoft:

2567616 Компилациите на SQL Server 2008 R2, които са издадени след издаването на SQL Server 2008 R2 Service Pack 1

Заобиколно решение

Microsoft препоръчва да не използвате никоя от тези функции в заявките си, когато става въпрос за паралелни планове, тъй като те не винаги са надеждни. Вместо това използвайте клаузата OUTPUT на командата INSERT, за да извлечете стойността на самоличността, както е показано в примера по-долу.

Пример за използване на клауза OUTPUT:

DECLARE @MyNewIdentityValues table(myidvalues int)  
declare @A table (ID int primary key)  
insert into @A values (1)  
declare @B table (ID int primary key identity(1,1), B int not null)  
insert into @B values (1)  
select  
    [RowCount] = @@RowCount,  
    [@@IDENTITY] = @@IDENTITY,  
    [SCOPE\_IDENTITY] = SCOPE\_IDENTITY()  
  
set statistics profile on  
insert into \_ddr\_T  
output inserted.ID into @MyNewIdentityValues  
    select  
            b.ID  
        from @A a  
            left join @B b on b.ID = 1  
            left join @B b2 on b2.B = -1  
  
            left join \_ddr\_T t on t.T = -1  
  
        where not exists (select \* from \_ddr\_T t2 where t2.ID = -1)  
set statistics profile off  
  
select  
    [RowCount] = @@RowCount,  
    [@@IDENTITY] = @@IDENTITY,  
    [SCOPE\_IDENTITY] = SCOPE\_IDENTITY(),  
    [IDENT\_CURRENT] = IDENT\_CURRENT('\_ddr\_T')  
select \* from @MyNewIdentityValues  
go

Ако вашата ситуация изисква да използвате някоя от тези функции, можете да използвате един от следните методи за заобиколно решение на проблема.

Метод 1:

Включете следната опция във вашата заявка

OPTION (MAXDOP 1)

Забележка: Това може да влоши производителността на част от заявката SELECT.

Метод 2:

Прочетете стойността от SELECT частта в набор от променливи (или променлива от една таблица) и след това я вмъкнете в целевата таблица с MAXDOP=1. Тъй като планът INSERT няма да е успореден, ще получите правилната семантика, но SELECT ще бъдете успоредни, за да постигнете желаната производителност.

Метод 3:

Изпълнете следната команда, за да зададете опцията за максимална степен на паралелизъм на 1:

sp\_configure 'max degree of parallelism', 1

go

reconfigure with override

go

Забележка: Този метод може да влоши производителността на сървъра. Не трябва да използвате този метод, освен ако не сте го оценили в тестова или постановъчна среда.

Повече информация

Грешка в Microsoft Connect за този проблем

Максимална степен на паралелизъм (MAXDOP)