Pourquoi IDENTITY_INSERT ON n'est-il autorisé que sur une table à la fois?

20

Il est possible que IDENTITY_INSERT ne puisse être défini sur ON que dans une table de base de données à la fois, mais pourquoi? Étant donné que les IDENTITYcolonnes ne sont pas uniques au monde, je ne peux penser à aucune situation dangereuse qui pourrait être causée par l'insertion d'identités dans plus d'une table en même temps (au moins pas plus dangereux que le fudging général avec IDENTITY INSERT).

L'IDENTIFICATION INSERT doit être rarement utilisée, mais quelle est la raison de la limite stricte?

Ben Brocka
la source
1
Peut-être dissuasif, donc il est rarement utilisé?
Remus Rusanu
@RemusRusanu c'est un peu ce à quoi je pensais, soit pour vous assurer de ne pas laisser accidentellement II ON pour plusieurs tables.
Ben Brocka
@Ben pourquoi le laisser accidentellement sur plusieurs tables est-il pire que de le laisser accidentellement sur une table? Les deux peuvent conduire au même type de problème. Je suis vraiment curieux de connaître votre question, et je ne pense pas que la dissuasion soit la réponse, sinon nous aurions beaucoup plus de restrictions dans le moteur. Mais je suis d'accord que si vous sentez que vous devez le faire souvent, il y a probablement quelque chose de suspect.
Aaron Bertrand
@AaronBertrand ce n'est pas le cas, comme je l'ai laissé entendre dans le Q. Pas sûr non plus de dissuader, car SQL Server autorise de nombreuses autres mauvaises pratiques comme nommer vos colonnes avec des mots clés réservés (parfois même si vous n'utilisez pas []!)
Ben Brocka
@Ben, ce n'était pas nécessairement pour vous, mais pour tout lecteur qui a rencontré la question.
Aaron Bertrand

Réponses:

12

Je pense que c'est pour le rendre difficile. Si vous pouviez simplement le laisser allumé tout le temps, pourquoi même avoir un champ d'identité?

Il existe cependant quelques restrictions:

  • Il persiste uniquement sur cette connexion
  • Il ne peut être réglé que sur une seule table par connexion

Sur la base des restrictions liées à la connexion, je pense que c'est principalement pour qu'il ne soit jamais accidentellement laissé sous tension.

Imaginez si quelqu'un a activé l'insertion d'ID sur l'une de vos tables, alors vous ne vous en êtes pas rendu compte et une insertion (normalement) non valide a été effectuée qui a brisé l'intégrité de votre champ ID?

Gardez à l'esprit que les champs ID peuvent avoir des valeurs en double s'il n'y a pas de contrainte ou d'index unique en place ...

JNK
la source
1
+1 Je pense que votre dernier point sur les doublons est beaucoup manqué. Les gens pensent que s'ils le définissent, IDENTITYcela devient également une contrainte unique. Très facile à réfuter, bien sûr, s'ils pensent essayer.
Aaron Bertrand
@AaronBertrand Mais encore une fois, le risque d'ID en double est exactement le même sur n'importe quelle table avec IDENTITY INSERT, pourquoi la limite stricte? Je pense que le fait qu'il persiste uniquement pour la connexion est beaucoup plus logique à titre de précaution.
Ben Brocka
Je ne suggérais pas que le problème d'identification en double était une raison de la limite stricte.
Aaron Bertrand
6

Je suppose que c'était une restriction en raison de la mise en œuvre. Autoriser ce paramètre sur plusieurs tables était un succès potentiel:

Puisqu'il s'agit d'un paramètre de session, permettre au paramètre d'être activé sur une seule table signifie qu'il s'agit d'un simple indicateur et de l'ID d'objet de la table à stocker sur la session, côté serveur. Peut-être que ce n'est qu'un seul entier: 0 si aucun IDENTITY_INSERT n'est actif, et un certain codage de databaseid + objectid pour la table.

Autoriser le paramètre à être défini sur plusieurs tables dans une session signifierait que le serveur stockerait une liste dynamique de ces objets et la vérifierait pour chaque instruction d'insertion. Imaginez qu'une session active le paramètre pour mille tables:

  1. Cela signifie que le serveur a alloué 1000 éléments dans la variable de session
  2. Cela signifie également que le serveur doit vérifier la liste des 1000 éléments pour chaque instruction d'insertion dans cette session.

Je soupçonne également que l'activation de identity_insert a un impact sur les performances sur le serveur. Dans sybase, il y avait un " facteur de définition de la gravure d'identité ", qui permettait de sauvegarder la valeur du compteur d'identité d'une table à sauvegarder une fois de temps en temps (la valeur est conservée en mémoire et écrite sur le disque de temps en temps et sur le serveur fermer ). SQL Server est basé sur le même code et a donc probablement une optimisation comparable, mais l'activation de identity_insert sur une table contraint probablement le serveur à enregistrer la valeur d'identité pour chaque insertion, car sinon il ne peut pas garantir une taille d'écart maximale. Donc, si une session fait un hit de performance sur les insertions dans une table, cela est probablement acceptable, mais pas si elle peut faire le hit de performance sur toutes les tables auto_increment sur le serveur.

Olivier S
la source
+1 Probablement une certaine vérité ici. Je n'achète pas l'argument de la taille de l'écart, car un seul INSERTpeut avoir lieu à la fois pour une session, et je pourrais facilement insérer 10 millions de IDENTITYvaleurs codées en dur .
Aaron Bertrand
La taille de l'écart est liée à ce qui se passe en cas de plantage: sur sybase, si le serveur plante, la dernière identité est perdue (il était en mémoire), donc il redémarre en laissant un espace (voir facteur de gravure d'identité)
Olivier S
Donc, dans SQL Server, suggérez-vous que quelque chose de différent se produit si le moteur se bloque lors de l'insertion de 1 000 000 de lignes avec une colonne d'identité, ou si vous remplacez la colonne d'identité avec 1 000 000 de valeurs codées en dur lorsque SET IDENTITY_INSERTest activé? Je suggère simplement que la taille de l'écart n'affecte pas plusieurs tables différemment de ce qu'elle affecte une seule table.
Aaron Bertrand
ma conjecture - je n'ai absolument aucune preuve de cela - est que SET IDENTITY_INSERT sur une table force une écriture sur disque de l'auto-incrémentation à chaque insertion. La raison serait que puisque la valeur que vous insérez peut être n'importe quoi, le serveur ne peut pas considérer "ok, si j'écris sur le disque seulement une fois toutes les 1000 lignes, en cas de plantage, je peux ajouter 1000 en toute sécurité à la dernière valeur que j'ai enregistrée"
Olivier S