Por que IDENTITY_INSERT ON é permitido apenas em uma tabela por vez?

20

É o caso de IDENTITY_INSERT só poder ser definido como ON em uma tabela de banco de dados por vez, mas por quê? Como as IDENTITYcolunas não são globalmente exclusivas, não consigo pensar em nenhuma situação perigosa que possa ser causada pela inserção de identidades em mais de uma tabela ao mesmo tempo (pelo menos não mais perigosa do que geralmente brincar com o IDENTITY INSERT).

O INSERT DE IDENTIDADE raramente deve ser usado, mas qual o motivo do limite rígido?

Ben Brocka
fonte
11
Dissuasor, talvez, por isso raramente é usado?
Remus Rusanu
@RemusRusanu, isso é o que eu estava pensando, isso ou para garantir que você não deixasse acidentalmente o II ON para várias tabelas.
Ben Brocka
@ Ben: por que deixá-lo acidentalmente em várias tabelas pior do que acidentalmente deixá-lo acidentalmente em uma tabela? Ambos podem levar ao mesmo tipo de problema. Estou genuinamente curioso sobre sua pergunta e não acho que a resposta seja a dissuasão, ou teríamos muito mais restrições no mecanismo. Mas concordo que, se você sente que precisa fazer isso com frequência, provavelmente há algo suspeito.
Aaron Bertrand
@AaronBertrand também não é, como sugeri no Q. Também não tenho certeza sobre o impedimento, já que o SQL Server permite muitas outras práticas ruins, como nomear suas colunas com palavras-chave reservadas (às vezes mesmo se você não usar []!)
Ben Brocka
@ Bem, isso não era necessariamente para você, mas para qualquer leitor que se deparou com a questão.
Aaron Bertrand

Respostas:

12

Eu acho que é para dificultar. Se você pudesse deixá-lo ligado o tempo todo, por que ter um campo de identidade?

Na verdade, existem algumas restrições:

  • Persiste apenas nessa conexão
  • É configurável apenas em uma tabela por conexão

Com base nas restrições relacionadas à conexão, acho que é principalmente para nunca ser acidentalmente ativado.

Imagine se alguém ativou a inserção de ID em uma de suas tabelas, então você não percebeu e uma inserção (normalmente) inválida foi executada que quebrou a integridade do seu campo de ID?

Lembre-se de que os campos de ID podem ter valores duplicados se não houver restrição ou índice exclusivo em vigor ...

JNK
fonte
11
+1 Acho que seu último ponto sobre duplicatas é muito esquecido. As pessoas pensam que se definirem IDENTITYisso também se tornará uma restrição única. É muito fácil refutar, é claro, se eles tentam.
Aaron Bertrand
@AaronBertrand Mas, novamente, o risco de ID duplicado é exatamente o mesmo em qualquer tabela com o IDENTITY INSERT ativado, por que o limite rígido? Eu acho que o fato de persistir apenas para a conexão faz muito mais sentido como precaução.
Ben Brocka
Eu não estava sugerindo que o problema de identificação duplicada fosse uma razão para o limite rígido.
Aaron Bertrand
6

Meu palpite é que isso foi uma restrição devido à implementação. Permitir essa configuração em várias tabelas foi um possível sucesso de desempenho:

Como esse é um parâmetro da sessão, permitir que a configuração seja ativada em uma única tabela significa que é um sinalizador simples e o ID do objeto da tabela para armazenar na sessão, no lado do servidor. Talvez este seja apenas um único número inteiro: 0 se nenhum IDENTITY_INSERT estiver ativo e alguma codificação de databaseid + objectid para a tabela.

Permitir que o parâmetro seja definido em várias tabelas em uma sessão significaria que o servidor armazenaria uma lista dinâmica de tais objetos e a verificaria para todas as instruções de inserção. Imagine que uma sessão ativa o parâmetro para mil tabelas:

  1. Isso significa que o servidor alocou 1000 itens na variável de sessão
  2. Isso significa também que o servidor deve verificar a lista dos 1000 itens para cada instrução de inserção nesta sessão.

Além disso, suspeito que o conjunto identity_insert on tenha um desempenho atingido no servidor. Na sybase, havia um " fator de conjunto de gravação de identidade ", que permitia salvar o valor do contador de identidade de uma tabela para ser salvo apenas de vez em quando (o valor é mantido na memória e gravado no disco de vez em quando e no servidor desligar ). O SQL Server é baseado no mesmo código, portanto, provavelmente possui uma otimização comparável, mas a ativação de identity_insert em uma tabela provavelmente restringe o servidor a salvar o valor da identidade para cada inserção, pois, caso contrário, não pode garantir um tamanho máximo de espaço. Portanto, se uma sessão faz um impacto no desempenho nas inserções em uma tabela, isso provavelmente é aceitável, mas não se ele pode causar o desempenho em todas as tabelas de incremento automático no servidor.

Olivier S
fonte
+1 Provavelmente alguma verdade aqui. Eu não compro o argumento do tamanho da lacuna, pois apenas um INSERTpode estar acontecendo por vez em uma sessão e eu poderia facilmente inserir 10 milhões de IDENTITYvalores codificados .
Aaron Bertrand
O tamanho do intervalo está relacionado ao que acontece em caso de falha: no sybase, se o servidor travar, a última identidade será perdida (estava na memória), reiniciando, deixando um intervalo (consulte fator de conjunto de gravação de identidade)
Olivier S
Então, no SQL Server, você está sugerindo que algo diferente aconteça se o mecanismo travar ao inserir 1.000.000 de linhas com uma coluna de identidade ou substituir a coluna de identidade por 1.000.000 de valores codificados enquanto SET IDENTITY_INSERTestiver ativado? Estou apenas sugerindo que o tamanho do espaço não afeta várias tabelas de maneira diferente do que afeta uma única tabela.
Aaron Bertrand
meu palpite - não tenho absolutamente nenhuma prova disso - é que SET IDENTITY_INSERT em uma tabela força uma gravação em disco do incremento automático em cada inserção. A lógica seria que, como o valor que você insere pode ser qualquer coisa, o servidor não pode considerar "ok, se eu gravar no disco apenas uma vez a cada 1000 linhas, em caso de falha, posso adicionar 1000 com segurança ao último valor que salvei"
Olivier S