SQL Server: Ist das Ändern der Sortierung in vorhandenen Datenbanken sicher?

7

Ich bin neu in SQL Server und war mir der Möglichkeit nicht bewusst, dass bei T-SQL die Groß- und Kleinschreibung nicht berücksichtigt wird.

Ich habe Entitäten normalisiert, indem ich Tabellen und Einschränkungen aufgeteilt habe. Ich habe Angst, dass, wenn ich die Sortierung jetzt ändere, einige dieser Einschränkungen ungültig sein können, wenn beispielsweise ein Fremdschlüsselwert ohne Berücksichtigung der Groß- und Kleinschreibung auf einen PK-Wert mit einer anderen Groß- und Kleinschreibung verweist.

Wenn ich diese Abfrage in der Datenbank ausführen würde (getestet in einer Basisdatenbank):

ALTER DATABASE <db_name>
COLLATE SQL_Latin1_General_Cp1_CS_AS ;
GO

Was würde passieren, wenn einige Einschränkungen verletzt würden?

Gibt es einen anderen Grund, warum ich vorsichtig sein sollte, eine datenbankweite Änderung vorzunehmen, z. B. die Sortierung zu ändern?

Zach Smith
quelle

Antworten:

6

Das Ändern der Sortierung einer Datenbank wirkt sich nicht auf vorhandene Spalten aus. Dies betrifft neue Nicht-XML-Zeichenfolgenspalten, die keine COLLATEKlausel (einschließlich Tabellenvariablen), Zeichenfolgenliterale und Variablenwerte angeben (keine Auflösung von Variablennamen, die durch die Sortierung auf Instanzebene bestimmt wird). Dies bedeutet, dass Folgendes betroffen ist:

IF (@Variable = 'string')
BEGIN
    ...
END;

Diese Änderung wirkt sich auch auf Metadaten auf Datenbankebene aus, z. B. Namen von Schemas, Objekten, Spalten, Indizes usw. Dies bedeutet, dass die folgenden zwei Szenarien betroffen sind:

SELECT ...
FROM   sys.indexes si
WHERE  si.[name] = N'somename'; -- real name = SomeName

und:

SELECT ...
FROM   dbo.sometable st -- real name = SomeTable

In beiden Beispielen würden sie in einer Sortierung ohne Berücksichtigung der Groß- und Kleinschreibung arbeiten, in einer Sortierung ohne Berücksichtigung der Groß- und Kleinschreibung jedoch nichts oder Fehler zurückgeben.

Schließlich, wie @JonathanFite war so freundlich, mich daran zu erinnern, die Änderung der DB Sortierungs kann Abfragen auswirken temporäre Tabellen beteiligt sind . Die Standardkollatierung für Zeichenfolgenspalten in temporären Tabellen (keine Tabellenvariablen) ist die Standardkollatierung für [tempdb](die [model]mit der Standardeinstellung der Instanz identisch sein sollte, es sei denn, jemand hat sie wiederhergestellt[model]von einem Server mit einer anderen Standardkollatierung), nicht der Kollatierung der lokalen Datenbank. Das heißt, obwohl die temporären Tabellen jedes Mal erstellt werden und Sie daher erwarten können, dass sie sich mit der neuen Sortierung wie "neu erstellte Tabellen" verhalten, verhalten sie sich tatsächlich wie "vorhandene Tabellen" und verhalten sich weiterhin wie zuvor die Sortieränderung. Wenn Sie Zeichenfolgenspalten in temporären Tabellen benötigen, um die neue Kollatierung zu verwenden, müssen Sie deren Kollatierung COLLATE DATABASE_DEFAULTin den CREATE TABLEAnweisungen explizit festlegen .

Daher müssen Sie wirklich viele Tests durchführen!

Wenn Sie vorhandene Spalten ändern möchten, müssen Sie vorhandene Einschränkungen löschen, eine ausgeben ALTER TABLE ... ALTER COLUMNund dann die Einschränkungen neu erstellen. Sie müssen auch Indizes neu erstellen, die eine Spalte verwenden, deren Sortierung geändert wurde, da die Sortierreihenfolge möglicherweise unterschiedlich ist.

Es ist auch am besten, keine Kollatierungen zu verwenden, die mit beginnen SQL_. Verwenden Sie stattdessen Latin1_General_100_CS_AS. Die Kollatierungen, die mit beginnen, SQL_sind seit der Veröffentlichung von SQL Server 2000 veraltet (auch wenn sie nicht offiziell veraltet sind) . Ihr Umgang mit VARCHAR/ 8-Bit-Daten ist veraltet und entspricht nicht dem neueren Verhalten. Aus Gründen der Abwärtskompatibilität war die Standardkollatierung für Installationen in US-Englisch leider die SQL_Latin1Kollatierung, wie auf der Seite MSDN für SQL Server-Kollatierungen verwenden angegeben :

Aus Gründen der Abwärtskompatibilität lautet die Standardkollatierung in englischer Sprache (US) SQL_Latin1_General *.

Dies wird auch im Standardkollatierungsdiagramm auf der Seite Kollatierungseinstellungen im Setup- MSDN vermerkt ( drücken Sie Strg-F und fügen Sie es ein sql_latin). Ich glaube, diese Standardeinstellung wurde ab SQL Server 2014 in eine Windows-Sortierung geändert, aber die Dokumentation verweist auch für das SQL Server 2016-Setup weiterhin auf die 2008 R2-Setup-Seite für Kollatierungen.


Unten finden Sie ein Skript, um einige der Verhaltensunterschiede beim Ändern der Sortierung einer Datenbank anzuzeigen:

USE [master];
GO

IF (DB_ID(N'ChangeDatabaseCollationTest') IS NULL)
BEGIN
    CREATE DATABASE [ChangeDatabaseCollationTest] COLLATE Latin1_General_100_CI_AS;
END;
GO

USE [ChangeDatabaseCollationTest];
GO
-- Current DB Collation: Latin1_General_100_CI_AS

EXEC sp_help 'sys.objects';
-- Collation for [name] = Latin1_General_100_CI_AS

IF ('A' = 'a')
BEGIN
    SELECT 'Case INsensitive comparison works.';
END;
ELSE
BEGIN
    SELECT 'Case INsensitive comparison did NOT work.';
END;
-- Case INsensitive comparison works.


CREATE TABLE dbo.CaseTest_a (ID INT); -- success
SELECT * FROM dbo.CaseTest_A; -- success


CREATE TABLE dbo.CaseTest_A (ID INT); -- error:
-- Msg 2714, Level 16, State 6, Line 5
-- There is already an object named 'CaseTest_A' in the database.




ALTER DATABASE [ChangeCollationTest] COLLATE Latin1_General_100_CS_AS; -- success

IF ('A' = 'a')
BEGIN
    SELECT 'Case INsensitive comparison works.';
END;
ELSE
BEGIN
    SELECT 'Case INsensitive comparison did NOT work.';
END;
-- Case INsensitive comparison did NOT work.


SELECT * FROM dbo.CaseTest_A; -- error:
-- Msg 208, Level 16, State 1, Line 56
-- Invalid object name 'dbo.CaseTest_A'.


CREATE TABLE dbo.CaseTest_A (ID INT); -- success

EXEC sp_help 'sys.objects';
-- Collation for [name] = Latin1_General_100_CS_AS


ALTER DATABASE [ChangeCollationTest] COLLATE Latin1_General_100_CI_AS; -- error:
-- Msg 1505, Level 16, State 1, Line 23
-- The CREATE UNIQUE INDEX statement terminated because a duplicate key was found for
--    the object name 'dbo.sysschobjs' and the index name 'nc1'. The duplicate key
--    value is (0, 1, CaseTest_A).
-- Msg 5072, Level 16, State 1, Line 23
-- ALTER DATABASE failed. The default collation of database 'ChangeCollationTest'
--    cannot be set to Latin1_General_100_CI_AS.
Solomon Rutzky
quelle
gute Antwort. Ich möchte auch hinzufügen, dass Vorsicht geboten ist, wenn die Datenbankkollatierung nicht mit der Serverkollatierung übereinstimmt. TempDB und damit auch alle temporären Tabellen verwenden standardmäßig die Server-Sortierung. Gespeicherte Prozeduren oder andere Befehle, die temporäre Tabellen verwenden, haben möglicherweise eine andere Sortierung als erwartet.
Jonathan Fite
@ JonathanFite Danke, dass du das erwähnt hast :). Ich habe weitere Informationen zu temporären Tabellen, Tabellenvariablen, Metadaten auf DB-Ebene usw. hinzugefügt.
Solomon Rutzky
2

Zunächst wird nichts passieren. Die Sortierung der Datenbank ist nur eine Standardeinstellung, die beim Erstellen in neue Spalten kopiert wird. Einmal erstellt, behalten sie diese Sortierung bei. Siehe sys.columns.collation_name .

Wenn Sie die Datenbankkollatierung ändern und dann neue Spalten erstellen, haben diese Spalten die neue Kollatierung. Dies kann eine Kollatierung sein, die mit den bereits vorhandenen Spalten kompatibel ist.

Wenn Sie eine Sortierung mit Groß- und Kleinschreibung für die Datenbank übernehmen, wird bei SQL zwischen Groß- und Kleinschreibung unterschieden. Objektnamen müssen genau mit den deklarierten Zeichenfolgen übereinstimmen. Dies kann die Anwendung beschädigen.

Ich habe diesen Prozess vor vielen Jahren durchlaufen. Ich scheine mich zu erinnern, dass ich jede Zeichenspalte in der Datenbank explizit auf die neue Sortierung ändern und dann die Daten für die Kollatierungsänderung aktualisieren musste (Aktualisierungstabelle set charcol1 = charcol1, charcol2 = charcol2 ...; Nicht-Zeichenfolge) Spalten wurden nicht benötigt). Dies war vor vielen Versionen, daher können die Dinge jetzt einfacher sein. Würde ich es je nach Größe und Komplexität erneut tun, wäre ich versucht, alle Objekte zu skripten, die Datei zu bearbeiten, um Kollatierungen zu entfernen, dann eine neue Datenbank von Grund auf neu zu erstellen und die Daten und Berechtigungen usw. zu übertragen.

Viel Glück.

Michael Green
quelle
Michael: Du hättest die UPDATEAussage nicht machen müssen, da das wirklich nichts an der Tabelle selbst ändern würde, da die Kollatierung nur Metadaten sind. Dies würde sich nur auswirken, wenn die Daten VARCHAR/ CHARund die neue Sortierung einer anderen Codepage zugeordnet wären . Ich vermute, das UPDATEwar ein umständlicher Weg, um die Indizes neu zu erstellen.
Solomon Rutzky