Qual é a melhor opção para obter o valor da identidade que acabei de gerar por meio de uma inserção? Qual é o impacto dessas declarações em termos de desempenho?
SCOPE_IDENTITY()
- Função agregada
MAX()
- SELECT
TOP 1
IdentityColumn FROM TableNameORDER BY IdentityColumn DESC
Respostas:
Use
SCOPE_IDENTITY()
se você estiver inserindo uma única linha e quiser recuperar o ID que foi gerado.Resultado:
Use a
OUTPUT
cláusula se estiver inserindo várias linhas e precisar recuperar o conjunto de IDs que foram gerados.Resultado:
Além do desempenho, esses são os únicos que garantem a correção no nível de isolamento padrão e / ou com vários usuários. Mesmo se você ignorar o aspecto de correção, o SQL Server retém o valor inserido
SCOPE_IDENTITY()
na memória, portanto, naturalmente, isso será mais rápido do que executar e executar sua própria consulta isolada na tabela ou nas tabelas do sistema.Ignorar o aspecto de correção é como dizer ao carteiro que ele fez um bom trabalho entregando as correspondências de hoje - ele terminou sua rota 10 minutos mais rápido que o tempo médio, o problema é que nenhuma das correspondências foi entregue na casa certa.
Não use nenhum dos seguintes:
@@IDENTITY
- como isso não pode ser usado em todos os cenários, por exemplo, quando uma tabela com uma coluna de identidade possui um gatilho que também é inserido em outra tabela com sua própria coluna de identidade - você receberá o valor errado.IDENT_CURRENT()
- Entro em detalhes sobre isso aqui , e os comentários também são úteis para leitura, mas essencialmente, com a concordância, você frequentemente obterá a resposta errada.MAX()
ouTOP 1
- você teria que proteger as duas instruções com isolamento serializável para garantir que o queMAX()
você recebe não seja de outra pessoa. Isso é muito mais caro do que apenas usarSCOPE_IDENTITY()
.Essas funções também falham sempre que você insere duas ou mais linhas e precisam de todos os valores de identidade gerados - sua única opção é a
OUTPUT
cláusula.fonte
Além do desempenho, todos eles têm significados bastante diferentes.
SCOPE_IDENTITY()
fornecerá o último valor de identidade inserido em qualquer tabela diretamente dentro do escopo atual (escopo = lote, procedimento armazenado, etc., mas não dentro, por exemplo, de um gatilho que foi disparado pelo escopo atual).IDENT_CURRENT()
fornecerá o último valor de identidade inserido em uma tabela específica de qualquer escopo, por qualquer usuário.@@IDENTITY
fornece o último valor de identidade gerado pela instrução INSERT mais recente para a conexão atual, independentemente da tabela ou escopo. (Observação: o Access usa essa função e, portanto, tem alguns problemas com gatilhos que inserem valores em tabelas com colunas de identidade.)Usar
MAX()
ouTOP 1
pode fornecer resultados totalmente errados se a tabela tiver uma etapa de identidade negativa ou se houver linhas inseridasSET IDENTITY_INSERT
em execução. Aqui está um script demonstrando tudo isso:Resumo: vara com
SCOPE_IDENTITY()
,IDENT_CURRENT()
ou@@IDENTITY
, e certifique-se que você está usando o que retorna o que você realmente precisa.fonte
IDENT_CURRENT()
e@@IDENTITY
quando seu próprio script demonstra que eles produzem resultados incorretos?IDENT_CURRENT()
retorna. MAX () nunca retorna o valor correto além da primeira linha, pois o id está contando para trás e, comIDENTITY_INSERT
ativado, 9005 não é um valor de identidade gerado , portanto, não é refletido porIDENT_CURRENT()
. Mas pode retornar resultados "incorretos" se você realmente estiver atrás do queSCOPE_IDENTITY()
retorna. Escolha a ferramenta certa para o trabalho.@@IDENTITY
quase nunca é a maneira ideal de gerar valores de identidade gerados. O ponto principal é queMAX()
ouTOP 1
são como uma versão menos confiávelIDENT_CURRENT()
, que é uma função perfeitamente adequada a ser usada se você entender o que faz. Pode ser útil para trabalhos de manutenção ou algo assim.