Sintomas
Quando utiliza funções SCOPE_IDENTITY() ou @@IDENTITYpara obter os valores inseridos numa coluna de identidade, poderá reparar que, por vezes, estas funções devolvem valores incorretos. O problema ocorre apenas quando as consultas utilizam planos de execução paralelos. Para obter mais informações sobre como determinar se as suas consultas vão utilizar planos de execução paralelos, consulte a secção paralelo de consultas intra-query no seguinte artigo técnico sobre Transferências da Microsoft:
Causa
A Microsoft confirmou que se trata de um problema nos produtos Microsoft listados no início deste artigo.
Resolução
Informações de atualização cumulativas
SQL Server 2008 R2 Service Pack 1
A correção para este problema foi lançada pela primeira vez na Atualização Cumulativa 5 para o SQL Server 2008 R2 Service Pack 1. Para obter mais informações sobre como obter este pacote de atualizações cumulativas, clique no número de artigo seguinte para ver o artigo na Base de Dados de Conhecimento Microsoft:
2659694Pacote de Atualização Cumulativa 5 para o SQL Server 2008 R2 Service Pack 1
NotaUma vez que as com builds são cumulativas, cada nova versão de correção contém todas as correções e todas as correções de segurança incluídas na correção anterior do SQL Server 2008 R2. Recomendamos que considere aplicar a versão de correção mais recente que contém esta correção. Para mais informações, clique no número de artigo que se segue para ver o artigo na Base de Dados de Conhecimento Microsoft:
2567616As com builds do SQL Server 2008 R2 lançadas após o SQL Server 2008 R2 Service Pack 1 ter sido lançado
Solução
A Microsoft recomenda que não utilize estas funções nas suas consultas quando existem planos paralelos envolvidos, uma vez que nem sempre são fiáveis. Em vez disso, utilize a cláusula OUTPUT da inserção INSERT para obter o valor de identidade conforme apresentado no exemplo abaixo.
Exemplo de utilização da cláusula OUTPUT:
DECLARE @MyNewIdentityValues tabela(myidvalues int)
declare @A tabela (chave primária ID int)
inserir em @A valores (1)
declare @B tabela (ID int identidade de chave primária(1,1), B int not null)
inserir em @B valores (1)
selecione
[ContaDeL linhas] = @@RowCount,
[@@IDENTITY] = @@IDENTITY,
[SCOPE_IDENTITY] = SCOPE_IDENTITY()
definir perfil de estatística em
inserir na _ddr_T
saída inserted.ID para @MyNewIdentityValues
selecione
b.ID
de @A a
associação à esquerda @B b na b.ID = 1
associação à @B b2 em b2. B = -1
associação à _ddr_T t no t.T = -1
onde não existe (selecione * _ddr_T t2 onde t2.ID = -1)
desajustar o perfil de estatística
selecione
[ContaDeL linhas] = @@RowCount,
[@@IDENTITY] = @@IDENTITY,
[SCOPE_IDENTITY] = SCOPE_IDENTITY(),
[IDENT_CURRENT] = IDENT_CURRENT('_ddr_T')
selecione * no @MyNewIdentityValues
ir
Se a sua situação exigir que utilize uma destas funções, pode utilizar um dos seguintes métodos para resolver o problema.
Método 1:
Inclua a seguinte opção na sua consulta
OPÇÃO (MAXDOP 1)
Nota:Isto poderá prejudicar o desempenho de SELECT parte da sua consulta.
Método 2:
Leia o valor da peça SELECT num conjunto de variáveis (ou uma única variável de tabela) e, em seguida, insira-o na tabela de destino com MAXDOP=1. Uma vez que o plano INSERT não será paralelo, terá a semântica certa, mas a sua SELEÇÃO estará paralelamente para obter o desempenho pretendido.
Método 3:
Execute a seguinte declaração para definir o grau máximo de opção de paraleloismo para 1:
sp_configure 'grau máximo de paralelo', 1
ir
reconfigurar com override
ir
Nota:este método pode causar degradação no desempenho no servidor. Não deverá utilizar este método a menos que o tenha avaliado num ambiente de teste ou teste.
Mais Informações
Grau Máximo de Paralelo (MAXDOP)https://msdn.microsoft.com/en-us/library/ms181007.aspx