Sintomas
Quando você usa funções SCOPE_IDENTITY() ou @@IDENTITYpara recuperar os valores inseridos em uma coluna de identidade, você pode notar que essas funções às vezes retornam valores incorretos. O problema ocorre somente quando suas consultas usam planos de execução paralelas. Para obter mais informações sobre como determinar se suas consultas usarão planos de execução paralelas, consulte a seção Paralelismo Intra-query no artigo técnico a seguir sobre Downloads da Microsoft:
Causa
A Microsoft confirmou que esse é um problema que ocorre nos produtos Microsoft listados no início deste artigo.
Resolução
Informações sobre a atualização cumulativa
SQL Server 2008 R2 Service Pack 1
A correção desse problema foi lançada pela primeira vez na Atualização Cumulativa 5 para SQL Server 2008 R2 Service Pack 1. Para obter mais informações sobre como obter esse pacote de atualização cumulativa, clique no seguinte número de artigo para exibir o artigo na Base de Dados de Conhecimento da Microsoft:
2659694Pacote de Atualização Cumulativa 5 para SQL Server 2008 R2 Service Pack 1
Observação Como as builds são cumulativas, cada nova versão de correção contém todos os hotfixes e todas as correções de segurança que foram incluídas na versão de correção do SQL Server 2008 R2 anterior. Recomendamos que você considere aplicar a versão de correção mais recente que contém esse hotfix. Para obter mais informações, clique no número abaixo para ler os artigos na Base de Dados de Conhecimento Microsoft:
2567616As SQL Server 2008 R2 que foram lançadas após SQL Server 2008 R2 Service Pack 1 foi lançado
Solução alternativa
A Microsoft recomenda que você não use nenhuma dessas funções em suas consultas quando os planos paralelos estão envolvidos, pois nem sempre são confiáveis. Em vez disso, use a cláusula OUTPUT da instrução INSERT para recuperar o valor de identidade, conforme mostrado no exemplo abaixo.
Exemplo de uso da cláusula OUTPUT:
DECLARE @MyNewIdentityValues table(myidvalues int)
declare @A tabela (ID int primary key)
inserir em @A valores (1)
declare @B tabela (ID int primary key identity(1,1), B int not null)
inserir em @B valores (1)
select
[RowCount] = @@RowCount,
[@@IDENTITY] = @@IDENTITY,
[SCOPE_IDENTITY] = SCOPE_IDENTITY()
definir o perfil de estatísticas em
inserir no _ddr_T
saída inserted.ID em @MyNewIdentityValues
select
b.ID
de @A um
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
onde não existe (selecione * de _ddr_T t2 onde t2.ID = -1)
definir o perfil de estatísticas desligado
select
[RowCount] = @@RowCount,
[@@IDENTITY] = @@IDENTITY,
[SCOPE_IDENTITY] = SCOPE_IDENTITY(),
[IDENT_CURRENT] = IDENT_CURRENT('_ddr_T')
select * from @MyNewIdentityValues
go
Se a sua situação exigir que você precise usar uma dessas funções, você poderá usar um dos seguintes métodos para contornar o problema.
Método 1:
Inclua a seguinte opção em sua consulta
OPÇÃO (MAXDOP 1)
Observação: isso pode prejudicar o desempenho da parte SELECT da consulta.
Método 2:
Leia o valor da parte SELECT em um conjunto de variáveis (ou uma única variável de tabela) e insira na tabela de destino com MAXDOP=1. Como o plano INSERT não será paralelo, você obterá a semântica correta, mas seu SELECT será paralelo para atingir o desempenho desejado.
Método 3:
Execute a seguinte instrução para definir o grau máximo da opção de paralelismo como 1:
sp_configure "grau máximo de paralelismo", 1
go
reconfigurar com substituição
go
Observação: esse método pode causar degradação de desempenho no servidor. Você não deve usar esse método, a menos que o tenha avaliado em um ambiente de teste ou preparação.