Symptom
När du använder antingen funktionerna SCOPE_IDENTITY() eller @@IDENTITY för att hämta värden som infogats i en identitetskolumn kanske du märker att dessa funktioner ibland returnerar felaktiga värden. Problemet uppstår bara när dina frågor använder parallella körningsplaner.
Orsak
Microsoft har bekräftat att detta är ett problem i de Microsoft-produkter som anges i början av den här artikeln.
Lösning
Information om kumulativ uppdatering
SQL Server 2008 R2 Service Pack 1
Korrigeringen för det här problemet släpptes först i kumulativ uppdatering 5 för SQL Server 2008 R2 Service Pack 1. Om du vill veta mer om hur du hämtar det här kumulativa uppdateringspaketet klickar du på följande artikelnummer och läser artikeln i Microsoft Knowledge Base:
2659694 Kumulativ uppdatering paket 5 för SQL Server 2008 R2 Service Pack 1
Anteckning Eftersom versionerna är kumulativa innehåller varje ny korrigeringsversion alla snabbkorrigeringar och alla säkerhetskorrigeringar som ingick i den tidigare SQL Server 2008 R2-korrigeringsversionen. Vi rekommenderar att du installerar den senaste snabbkorrigeringen som innehåller den här snabbkorrigeringen. Mer information om hur du åtgärdar det här problemet får du om du klickar på följande artikelnummer i Microsoft Knowledge Base:
2567616 SQL Server 2008 R2-versionerna som släpptes efter att SQL Server 2008 R2 Service Pack 1 släpptes
Lösning
Microsoft rekommenderar att du inte använder någon av dessa funktioner i dina frågor när parallella abonnemang är inblandade, eftersom de inte alltid är tillförlitliga. Använd i stället OUTPUT-satsen i INSERT-instruktionen för att hämta identitetsvärdet som du ser i exemplet nedan.
Exempel på hur du använder OUTPUT-satsen:
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
Om din situation kräver att du behöver använda någon av dessa funktioner kan du använda någon av följande metoder för att lösa problemet.
Metod 1:
Ta med följande alternativ i frågan
OPTION (MAXDOP 1)
Obs! Detta kan skada prestandan för SELECT-delen av frågan.
Metod 2:
Läs in värdet från SELECT Part i en uppsättning variabler (eller en enskild tabellvariabel) och infoga det sedan i måltabellen med MAXDOP=1. Eftersom INSERT-planen inte kommer att vara parallell får du rätt semantik, men din SELECT kommer att vara parallell för att uppnå önskad prestanda.
Metod 3:
Kör följande uttryck för att ange den maximala graden av parallellitet till 1:
sp\_configure 'max degree of parallelism', 1
go
reconfigure with override
go
Obs! Den här metoden kan orsaka försämrade prestanda på servern. Du bör inte använda den här metoden om du inte har utvärderat den i en test- eller mellanlagringsmiljö.