web-dev-qa-db-ja.com

SQL Server:既存のデータベースの照合を変更しても安全ですか?

私はSQL Serverを使い始めたばかりで、T-SQLで大文字と小文字が区別される可能性を認識していませんでした。

テーブルと制約を分割してエンティティを正規化しています。ここで照合順序を変更すると、たとえば、「大文字と小文字を区別しない」外部キー値が大文字と小文字が異なるPK値を指す場合、これらの制約の一部が無効になる可能性があるのではないかと怖いです。

このクエリをDBで実行する場合(基本的なデータベースでテスト済み):

ALTER DATABASE <db_name>
COLLATE SQL_Latin1_General_Cp1_CS_AS ;
GO

いくつかの制約に違反するとどうなりますか?

照合順序の変更など、データベース全体の変更を慎重に行う必要がある他の理由はありますか?

7
Zach Smith

データベースの照合順序を変更しても、既存の列には影響しません。 COLLATE句(テーブル変数を含む)、文字列リテラル、および変数値(インスタンスレベルの照合で決定される変数の名前解決ではない)を指定しない、作成された新しい非XML文字列列に影響します。 。つまり、次のようなものが影響を受けます。

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

この変更は、スキーマの名前、オブジェクト、列、インデックスなど、データベースレベルのメタデータにも影響します。つまり、次の2つのシナリオが影響を受けます。

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

そして:

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

これらの例の両方で、大文字と小文字を区別しない照合順序で機能しますが、大文字と小文字を区別する照合順序ではそれぞれ何もエラーを返しません。

最後に、@ JonathanFiteは私に思い出させるほど親切でしたので、DB照合を変更するとmay一時テーブルを含むクエリに影響を与えます。一時テーブル(テーブル変数ではない)の文字列列のデフォルトの照合順序は、[tempdb]のデフォルトの照合順序([model]と同じである必要があります。これは、誰かが[model]ローカルデータベースの照合順序ではなく、デフォルトの照合順序が異なるサーバーから。つまり、一時テーブルは毎回作成されるため、新しいCollat​​ionでは「新しく作成されたテーブル」のように動作することが予想されますが、実際には「既存のテーブル」のように動作し、以前と同じように動作し続けます。照合順序の変更。新しいCollat​​ionを使用するために一時テーブルの文字列列が必要な場合は、COLLATE DATABASE_DEFAULTステートメントのCREATE TABLEを使用して、それらのCollat​​ionを明示的に設定する必要があります。

したがって、本当に多くのテストを行う必要があります!

既存の列を変更する場合は、既存の制約を削除し、ALTER TABLE ... ALTER COLUMNを発行して、制約を再作成する必要があります。また、並べ替え順序が異なる場合があるため、照合順序が変更された列を使用するインデックスを再構築する必要があります。

また、SQL_で始まる照合を使用しないことをお勧めします。代わりにLatin1_General_100_CS_ASを使用してください。 SQL Server2000がリリースされて以来、SQL_で始まる照合順序は廃止されました(正式に廃止されていなくても)。 VARCHAR/8ビットデータの処理は廃止されており、新しい動作に対応していません。残念ながら、下位互換性の理由から、 SQL Server照合の使用 MSDNページに記載されているように、米国英語インストールのデフォルトの照合はSQL_Latin1照合でした。

下位互換性のために、デフォルトの英語(US)照合はSQL_Latin1_General *です。

これは セットアップの照合設定 MSDNページのデフォルトの照合チャートにも記載されています(Control-Fを押し、sql_latinに貼り付けます)。このデフォルトはSQL Server 2014以降のWindows照合順序に変更されたと思いますが、ドキュメントは、SQL Server 2016セットアップの場合でも、照合順序の2008 R2セットアップページを示しています。


以下は、データベースの照合順序を変更したときの動作の違いを確認するためのスクリプトです。

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.
6
Solomon Rutzky

最初は何も起こりません。データベースの照合順序は、作成時に新しい列にコピーされるデフォルトにすぎません。作成されると、それらはその照合を保持します。 sys.columns.collat​​ion_name を参照してください。

データベースの照合順序を変更してから新しい列を作成すると、それらの列には新しい照合順序が適用されます。これは、既存の列との照合順序の互換性がある場合とない場合があります。

DBで大文字と小文字を区別する照合を採用すると、SQLで大文字と小文字が区別されます。オブジェクト名は、宣言された文字列と正確に一致する必要があります。これにより、アプリケーションが壊れる可能性があります。

私は何年も前にこのプロセスを経験しました。 DB内のすべての文字列を新しい照合順序に明示的に変更し、照合順序変更のデータを更新してキックインする必要があったことを覚えているようです(更新テーブルセットcharcol1 = charcol1、charcol2 = charcol2 ...;非文字列列は必要ありませんでした)。これは多くのバージョン前のものだったので、今はもっと簡単かもしれません。サイズと複雑さによっては、もう一度やり直したいのですが、すべてのオブジェクトのスクリプトを作成し、ファイルを編集して照合順序を削除し、新しいDBを最初から構築して、データと権限などを転送したいと思います。

幸運を。

2
Michael Green