Warum ist IDENTITY_INSERT ON jeweils nur für eine Tabelle zulässig?

20

Es ist der Fall, dass IDENTITY_INSERT immer nur in einer Datenbanktabelle auf ON gesetzt werden kann, aber warum? Da IDENTITYSpalten nicht global eindeutig sind, kann ich mir keine gefährliche Situation vorstellen, die durch das gleichzeitige Einfügen von Identitäten in mehr als eine Tabelle verursacht werden könnte (zumindest nicht gefährlicher als das generelle Verwechseln mit IDENTITY INSERT).

IDENTITY INSERT sollte selten verwendet werden, aber was ist der Grund für das harte Limit?

Ben Brocka
quelle
1
Vielleicht abschreckend, wird es also selten verwendet?
Remus Rusanu
@RemusRusanu das ist eine Art, was ich dachte, entweder das oder um sicherzustellen, dass Sie nicht versehentlich II ON für mehrere Tabellen verlassen.
Ben Brocka
@Ben Warum ist es schlimmer, wenn Sie es versehentlich für mehrere Tabellen aktiviert lassen, als wenn Sie es versehentlich für eine Tabelle aktiviert lassen? Beides kann zu demselben Problem führen. Ich bin aufrichtig neugierig auf Ihre Frage, und ich glaube nicht, dass Abschreckung die Antwort ist, sonst hätten wir viel mehr Einschränkungen im Motor. Aber ich stimme zu, dass, wenn Sie das Gefühl haben, dies oft tun zu müssen, es wahrscheinlich etwas Verdächtiges gibt.
Aaron Bertrand
@AaronBertrand ist es nicht, wie ich im Q angedeutet habe. Ich bin mir auch nicht sicher über Abschreckung, da SQL Server viele andere schlechte Praktiken wie das Benennen Ihrer Spalten mit reservierten Schlüsselwörtern zulässt (manchmal sogar, wenn Sie nicht [] verwenden!)
Ben Brocka
@Ben richtig, das war nicht unbedingt für dich, sondern für jeden Leser, der auf die Frage gestoßen ist.
Aaron Bertrand

Antworten:

12

Ich denke, es soll es schwierig machen. Wenn Sie es einfach die ganze Zeit eingeschaltet lassen könnten, warum dann überhaupt ein Identitätsfeld?

Tatsächlich gibt es jedoch einige Einschränkungen:

  • Es bleibt nur bei dieser Verbindung bestehen
  • Es kann nur für eine Tabelle pro Verbindung festgelegt werden

Aufgrund der Verbindungseinschränkungen denke ich, dass es hauptsächlich so ist, dass es niemals versehentlich eingeschaltet bleibt.

Stellen Sie sich vor, wenn jemand die ID-Einfügung für eine Ihrer Tabellen aktiviert hat, haben Sie nicht bemerkt, dass eine (normalerweise) ungültige Einfügung durchgeführt wurde, die die Integrität Ihres ID-Felds verletzt hat?

Beachten Sie, dass ID-Felder doppelte Werte haben können, wenn keine Einschränkung oder eindeutiger Index vorhanden ist ...

JNK
quelle
1
+1 Ich denke, dass Ihr letzter Punkt zu Duplikaten um ein Vielfaches verfehlt wird. Die Leute denken, wenn sie es setzen, wird IDENTITYes auch eine einzigartige Einschränkung. Sehr leicht zu widerlegen, natürlich, wenn sie es trotzdem versuchen.
Aaron Bertrand
@AaronBertrand Aber auch hier ist das Risiko doppelter IDs bei allen Tabellen mit aktivierter IDENTITY INSERT-Option genau gleich. Warum das harte Limit? Ich denke, dass die Tatsache, dass es nur für die Verbindung besteht, als Vorsichtsmaßnahme viel sinnvoller ist.
Ben Brocka
Ich habe nicht vorgeschlagen, dass das Problem der doppelten ID ein Grund für das harte Limit ist.
Aaron Bertrand
6

Ich vermute, dass dies eine Einschränkung aufgrund der Implementierung war. Das Zulassen dieser Einstellung für mehrere Tische war ein potenzieller Leistungstreffer:

Da dies ein Sitzungsparameter ist, bedeutet das Aktivieren der Einstellung für eine einzelne Tabelle, dass es sich um ein einfaches Flag handelt und die Objekt-ID der Tabelle in der Sitzung serverseitig gespeichert werden soll. Möglicherweise ist dies nur eine einzelne Ganzzahl: 0, wenn kein IDENTITY_INSERT aktiv ist, und eine Codierung von databaseid + objectid für die Tabelle.

Das Zulassen des Parameters für mehrere Tabellen in einer Sitzung würde bedeuten, dass der Server eine dynamische Liste solcher Objekte speichert und diese für jede Einfügeanweisung überprüft. Stellen Sie sich vor, eine Sitzung aktiviert den Parameter für tausend Tabellen:

  1. Dies bedeutet, dass der Server der Sitzungsvariablen 1000 Elemente zugewiesen hat
  2. Dies bedeutet auch, dass der Server die Liste der 1000 Elemente für jede Einfügeanweisung in dieser Sitzung überprüfen muss.

Ich vermute auch, dass set identity_insert on einen performanceübergreifenden Performance-Hit auf dem Server hat. In sybase gab es einen " Identity Burning Set Factor ", der es erlaubte, den Wert des Identitätszählers einer Tabelle nur einmal zu speichern (der Wert wird im Speicher gehalten und von Zeit zu Zeit und auf dem Server auf die Festplatte geschrieben) ausschalten ). SQL Server basiert auf demselben Code und weist daher wahrscheinlich eine vergleichbare Optimierung auf. Wenn Sie jedoch identity_insert für eine Tabelle aktivieren, muss der Server möglicherweise den Identitätswert für jede Einfügung speichern, da sonst keine maximale Lückengröße garantiert werden kann. Wenn also eine Sitzung einen Leistungstreffer für die Einfügungen in einer Tabelle erzielt, ist dies wahrscheinlich akzeptabel, aber nicht, wenn der Leistungstreffer für alle auto_increment-Tabellen auf dem Server erzielt werden kann.

Olivier S
quelle
+1 Wahrscheinlich etwas Wahres hier. Ich kaufe mir das Argument für die Lückengröße nicht, da immer nur INSERTeine Sitzung durchgeführt werden kann und ich problemlos 10 Millionen hartcodierte IDENTITYWerte einfügen könnte .
Aaron Bertrand
Die Spaltgröße bezieht , was im Fall von Crash passiert: auf sybase, wenn der Server die letzte Identität Absturz verloren geht (es war im Speicher), so startet es eine Lücke zu verlassen (Identität brennend eingestellten Faktor sehen)
Olivier S
Schlagen Sie also in SQL Server vor, dass etwas anderes passiert, wenn das Modul abstürzt, während 1.000.000 Zeilen mit einer Identitätsspalte eingefügt werden, oder wenn die Identitätsspalte mit 1.000.000 fest codierten Werten überschrieben wird, während SET IDENTITY_INSERTaktiviert ist? Ich schlage nur vor, dass die Lückengröße mehrere Tabellen nicht anders beeinflusst als eine einzelne Tabelle.
Aaron Bertrand
Ich vermute, ich habe absolut keinen Beweis dafür, dass SET IDENTITY_INSERT für eine Tabelle bei jeder Einfügung ein Schreiben auf die Festplatte des automatischen Inkrements erzwingt. Der Grund wäre, dass , da der Wert einfügen Sie kann alles sein, der Server nicht berücksichtigen kann „ok, wenn ich nur einmal alle 1000 Zeilen auf der Festplatte schreiben, bei Absturz kann ich sicher 1000 zum letzten Wert hinzufügen , ich gerettet“
Olivier S