Felaktiga värden kan visas när du använder SCOPE_IDENTITY() och @@IDENTITY

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ö.

Mer information

Microsoft Connect-bugg för det här problemet

Maximal grad av parallellitet (MAXDOP)