Warum wird das Entfernen der Identitätseigenschaft in einer Spalte nicht unterstützt?

11

Ich habe gelesen, dass nach SQL Server 2000 die Möglichkeit, eine Identitätsspalte zu "entidentifizieren", entfernt wurde. Und dass dies "By Design" war (nicht nur eine fehlende Funktion).

Hier ist ein Beispiel, das ich in einem Blog gefunden habe . Dabei werden die Systemtabellen aktualisiert. (Und diese Fähigkeit wurde nach SQL Server 2000 entfernt.) Ich verstehe, dass dies keine gute Idee ist, dies über Systemtabellen zu tun. Ich frage mich nur, warum es keine Funktion gibt, um dies auf andere Weise zu tun.

Das zu umgehen wird mir eine beträchtliche Menge Arbeit verursachen. (Kopieren von vielen hundert Millionen Zeilen in neue Tabellen in einer Umgebung mit Ausfallzeitunverträglichkeit.)

Also dachte ich, ich würde fragen "Warum".

Was hat sich in SQL Server 2005 und späteren Versionen geändert, was dies zu einer schlechten Sache gemacht hat? Oder war es immer schlecht und einfach nicht abgeschlossen?

Welche "Best Practice" (oder ein ähnliches Prinzip) würde verletzt, wenn eine Identitätsspalte wieder zu einer normalen Spalte gemacht würde?

- -

Update zur Beantwortung der Anfrage "Warum mache ich das?":
Dies ist eine Zusammenfassung auf sehr hoher Ebene: Ich werde anfangen, meinen Tabellen Partitionen hinzuzufügen. (Damit ich alte Daten archivieren / löschen kann.) Das ist alles einfach. Gelegentlich muss ich jedoch einen Datensatz auf eine andere Partition verschieben, damit er nicht entfernt wird (wenn eine Partition zum Archivieren / Löschen angezeigt wird). (Ich habe meine Partitionierungsspalte um 2 erhöht, sodass immer Platz vorhanden ist, um die Zeile auf eine andere Partition zu verschieben.)

Wenn die Partitionierungsspalte jedoch eine Identitätsspalte ist, muss ich den Wert löschen und erneut einfügen (es gibt keine Möglichkeit, den Wert einer Identitätsspalte zu aktualisieren). Was Probleme mit der Replikation verursacht.

Ich möchte also eine Sequenz anstelle einer Identitätsspalte verwenden. Bei großen Datenbanken ist dieser Wechsel jedoch sehr, sehr schwierig.

Vaccano
quelle

Antworten:

22

Ihre Frage lautet im Wesentlichen:

Warum kann ich dieses riskante Ding, das ich eigentlich nie hätte machen dürfen, nicht mehr tun?

Die Antwort auf diese Frage ist weitgehend irrelevant (obwohl Sie einige Microsoft-Kommentare in diesen Connect-Elementen sehen können, in denen nach dieser Funktionalität gefragt wird: # 294193 und # 252226). Der Vollständigkeit halber lautet meine Zusammenfassung: Die Fähigkeit, die Identitätseigenschaft zu entfernen, war ein unbeabsichtigter Nebeneffekt der Fähigkeit, überhaupt mit den Systemtabellen herumzuspielen. Dies sollte nicht auf die vielfältigen Arten verwendet werden, die oft sehr schlimme Folgen hatten, und wurde daher entfernt. Es war ein undokumentierter, nicht unterstützter Systemtabellen-Hack. Die Möglichkeit, Daten in Systemtabellen zu ändern, wurde nicht entfernt, da Microsoft nicht mehr wollte, dass Sie sich aus einer Spalte als Identitätsspalte heraushacken. Sie wurde entfernt, da das Durcheinander mit den Systemtabellen äußerst riskant ist. Das Entfernen der IDENTITY-Eigenschaft selbst war keine gezielte Entfernung von Features, und ich hätte diesem Ansatz auch in den alten Tagen, als dies möglich war, nie voll vertraut.

Wie wäre es, wenn wir stattdessen diese Frage beantworten?

Wie entferne ich die IDENTITY-Eigenschaft einer Spalte mit minimalen oder keinen Ausfallzeiten?

Dies können Sie ganz einfach mit ALTER TABLE ... SWITCHeiner Technik tun, die ich sicher zuerst von unserem eigenen Paul White in den Problemumgehungen für Connect # 252226 gelernt habe . Ein kurzes Beispiel anhand dieser einfachen Tabelle:

CREATE TABLE dbo.Original
(
  ID INT IDENTITY(1,1) PRIMARY KEY,
  name SYSNAME
);
GO

INSERT dbo.Original(name) VALUES(N'foo'),(N'bar');
GO

SELECT * FROM dbo.Original;
GO

Ergebnisse:

ID  name
--  ----
1   foo
2   bar

Lassen Sie uns nun eine Schattentabelle erstellen und zu dieser wechseln, dann die alte Tabelle löschen, die neue umbenennen und dann die normale Aktivität fortsetzen:

CREATE TABLE dbo.New
(
  ID INT PRIMARY KEY,
  name SYSNAME
);
GO

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
  ALTER TABLE dbo.Original SWITCH TO dbo.New;
  DROP TABLE dbo.Original;
  EXEC sys.sp_rename N'dbo.New', N'Original', 'OBJECT';
COMMIT TRANSACTION;
GO

INSERT dbo.Original(ID,name) VALUES(3,N'splunge');
UPDATE dbo.Original SET ID = 6 WHERE ID = 1;
GO

SELECT * FROM dbo.Original;
GO

Ergebnisse:

ID  name
--  -------
2   bar
3   splunge
6   foo

Jetzt aufräumen:

DROP TABLE dbo.Original;

Dies ist nur eine Metadatenoperation ohne Datenverschiebung und blockiert nur andere Benutzer, während die Metadaten aktualisiert werden. Zugegeben, es ist ein sehr vereinfachtes Beispiel. Wenn Sie über Fremdschlüssel verfügen oder andere Funktionen wie Replikation, Datenerfassung ändern, Änderungsverfolgung usw. verwenden, müssen Sie möglicherweise einige davon deaktivieren oder entfernen, bevor Sie diese Änderung vornehmen (ich habe nicht alle Kombinationen getestet). Informationen zu Fremdschlüsseln finden Sie in diesem Tipp, in dem gezeigt wird, wie Skripts generiert werden, um alle (oder ausgewählte) Fremdschlüsseleinschränkungen zu löschen und neu zu erstellen.

Darüber hinaus müssen Sie Ihren Anwendungscode aktualisieren, damit SQL Server diese Spalte nicht ausfüllt, und alle Anweisungen zum Einfügen oder Auswählen überprüfen, die möglicherweise von der Reihenfolge der Spalten oder den Spalten abhängen, die sie angeben müssen. Im Allgemeinen würde ich Ihre gesamte Codebasis nach einer Erwähnung dieser Tabelle durchsuchen.

In diesem Skript von Itzik Ben-Gan (Quelle: dieser alte Artikel ) finden Sie auch eine andere Möglichkeit, dies zu handhaben. Hier ist jedoch eine Datenverschiebung erforderlich, sodass die Anforderung "Keine oder minimale Ausfallzeiten" nicht erfüllt wird.

Aaron Bertrand
quelle
3
Ich möchte jeden, der vorbeikommt, ermutigen, die beiden Verbindungselemente zu verbessern. Wie schwer kann es sein, eine ALTER COLUMN-Funktion zu implementieren, die den Identitätsbooleschen Wert ein- oder ausschaltet?! Schmerzhaft zu umgehen.
usr
Ich muss zugeben, aus irgendeinem Grund dachte ich, dass das ..SWITCH..nur für Tabellen funktioniert, für die mindestens eine Partition definiert wurde.
RBarryYoung
Ich möchte nur hinzufügen, dass SWITCHkeine Enterprise Edition erforderlich ist, obwohl dies bei der Tabellenpartitionierung der Fall ist.
Dan Guzman