SQL 2005 [インスタンスとDBの照合順序はSQL_Latin1_General_CP1_CI_AS
]からSQL 2008 [デフォルトはLatin1_General_CI_AS
]に移行します。
SQL 2008 R2のインストールを完了し、デフォルトのLatin1_General_CI_AS
照合を使用しましたが、データベースの復元はSQL_Latin1_General_CP1_CI_AS
のままです。例外的な問題が発生しました-dbがLatin1_General_CI_AS
にあったときに#tempテーブルがSQL_Latin1_General_CP1_CI_AS
にあり、ここが私が今いる場所です-落とし穴に関するアドバイスが必要です。
SQL 2008 R2のインストール時に、'SQL Collation, used for backwards compatibility'
を使用するオプションがあります。2005データベースと同じ照合を選択するオプションがあります:SQL_Latin1_General_CP1_CI_AS
。
これにより、#tempテーブルで問題が発生しなくなりますが、落とし穴はありますか?
SQL 2008の "現在の"照合順序を使用しないと、機能や種類が失われますか?
いつかLatin1_General_CI_AS
に行かざるを得ませんか?
一部のDBAのスクリプトが完全なデータベースの行を完了し、新しい照合を使用してデータベースに挿入スクリプトを実行することを読みました-非常に怖くてこれに警戒しています-これを行うことをお勧めしますか?
まず、照合、並べ替え順序、コードページなどの用語について人々が話し合うときは、依然として多くの混乱があると私は感じているので、このような長い回答に対する謝罪です。
From [〜#〜] bol [〜#〜] から:
SQL Serverの照合順序は、データの並べ替えルール、大文字と小文字、およびアクセントの区別のプロパティを提供します。 charやvarcharなどの文字データ型で使用される照合順序は、そのデータ型で表すことができるコードページと対応する文字を指定します。 SQL Serverの新しいインスタンスをインストールする場合でも、データベースバックアップを復元する場合でも、サーバーをクライアントデータベースに接続する場合でも、作業するデータのロケール要件、並べ替え順序、大文字と小文字、アクセントの区別を理解することが重要です。 。
これは、データの文字列を並べ替えて比較する方法に関する規則を指定する照合が非常に重要であることを意味します。
注: [〜#〜] collationproperty [〜#〜] に関する詳細情報
ここで、まず違いを理解しましょう……
T-SQLの下で実行:
_SELECT *
FROM::fn_helpcollations()
WHERE NAME IN (
'SQL_Latin1_General_CP1_CI_AS'
,'Latin1_General_CI_AS'
)
GO
SELECT 'SQL_Latin1_General_CP1_CI_AS' AS 'Collation'
,COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'CodePage') AS 'CodePage'
,COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'LCID') AS 'LCID'
,COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'ComparisonStyle') AS 'ComparisonStyle'
,COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'Version') AS 'Version'
UNION ALL
SELECT 'Latin1_General_CI_AS' AS 'Collation'
,COLLATIONPROPERTY('Latin1_General_CI_AS', 'CodePage') AS 'CodePage'
,COLLATIONPROPERTY('Latin1_General_CI_AS', 'LCID') AS 'LCID'
,COLLATIONPROPERTY('Latin1_General_CI_AS', 'ComparisonStyle') AS 'ComparisonStyle'
,COLLATIONPROPERTY('Latin1_General_CI_AS', 'Version') AS 'Version'
GO
_
結果は次のようになります。
上記の結果を見ると、唯一の違いは2つの照合順序の並べ替え順ですが、それは正しくありません。その理由は以下のとおりです。
テスト1:
_--Clean up previous query
IF OBJECT_ID('Table_Latin1_General_CI_AS') IS NOT NULL
DROP TABLE Table_Latin1_General_CI_AS;
IF OBJECT_ID('Table_SQL_Latin1_General_CP1_CI_AS') IS NOT NULL
DROP TABLE Table_SQL_Latin1_General_CP1_CI_AS;
-- Create a table using collation Latin1_General_CI_AS
CREATE TABLE Table_Latin1_General_CI_AS (
ID INT IDENTITY(1, 1)
,Comments VARCHAR(50) COLLATE Latin1_General_CI_AS
)
-- add some data to it
INSERT INTO Table_Latin1_General_CI_AS (Comments)
VALUES ('kin_test1')
INSERT INTO Table_Latin1_General_CI_AS (Comments)
VALUES ('Kin_Tester1')
-- Create second table using collation SQL_Latin1_General_CP1_CI_AS
CREATE TABLE Table_SQL_Latin1_General_CP1_CI_AS (
ID INT IDENTITY(1, 1)
,Comments VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS
)
-- add some data to it
INSERT INTO Table_SQL_Latin1_General_CP1_CI_AS (Comments)
VALUES ('kin_test1')
INSERT INTO Table_SQL_Latin1_General_CP1_CI_AS (Comments)
VALUES ('Kin_Tester1')
--Now try to join both tables
SELECT *
FROM Table_Latin1_General_CI_AS LG
INNER JOIN Table_SQL_Latin1_General_CP1_CI_AS SLG ON LG.Comments = SLG.Comments
GO
_
テスト1の結果:
_Msg 468, Level 16, State 9, Line 35
Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "Latin1_General_CI_AS" in the equal to operation.
_
上記の結果から、異なる照合順序の列の値を直接比較できないことがわかります。列の値を比較するには、COLLATE
を使用する必要があります。
テスト2:
Erland Sommarskogが msdnに関するこの議論 で指摘しているように、主な違いはパフォーマンスです。
_--Clean up previous query
IF OBJECT_ID('Table_Latin1_General_CI_AS') IS NOT NULL
DROP TABLE Table_Latin1_General_CI_AS;
IF OBJECT_ID('Table_SQL_Latin1_General_CP1_CI_AS') IS NOT NULL
DROP TABLE Table_SQL_Latin1_General_CP1_CI_AS;
-- Create a table using collation Latin1_General_CI_AS
CREATE TABLE Table_Latin1_General_CI_AS (
ID INT IDENTITY(1, 1)
,Comments VARCHAR(50) COLLATE Latin1_General_CI_AS
)
-- add some data to it
INSERT INTO Table_Latin1_General_CI_AS (Comments)
VALUES ('kin_test1')
INSERT INTO Table_Latin1_General_CI_AS (Comments)
VALUES ('kin_tester1')
-- Create second table using collation SQL_Latin1_General_CP1_CI_AS
CREATE TABLE Table_SQL_Latin1_General_CP1_CI_AS (
ID INT IDENTITY(1, 1)
,Comments VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS
)
-- add some data to it
INSERT INTO Table_SQL_Latin1_General_CP1_CI_AS (Comments)
VALUES ('kin_test1')
INSERT INTO Table_SQL_Latin1_General_CP1_CI_AS (Comments)
VALUES ('kin_tester1')
_
---両方のテーブルにインデックスを作成します
_CREATE INDEX IX_LG_Comments ON Table_Latin1_General_CI_AS(Comments)
go
CREATE INDEX IX_SLG_Comments ON Table_SQL_Latin1_General_CP1_CI_AS(Comments)
_
---クエリを実行します
_DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_Latin1_General_CI_AS WHERE Comments = 'kin_test1'
GO
_
---これは暗黙的な変換になります
---クエリを実行します
_DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_SQL_Latin1_General_CP1_CI_AS WHERE Comments = 'kin_test1'
GO
_
---これは[〜#〜] not [〜#〜] IMPLICIT変換します
暗黙的な変換の理由は、データベースとサーバーの照合順序が_SQL_Latin1_General_CP1_CI_AS
_であり、テーブルTable_Latin1_General_CI_ASに列CommentsがVARCHAR(50)
として定義されているためです。 COLLATE Latin1_General_CI_ASを使用するため、ルックアップ中にSQL ServerはIMPLICIT変換を行う必要があります。
テスト3:
同じ設定で、varchar列をnvarchar値と比較して、実行プランの変更を確認します。
-クエリを実行します
_DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_Latin1_General_CI_AS WHERE Comments = (SELECT N'kin_test1' COLLATE Latin1_General_CI_AS)
GO
_
-クエリを実行します
_DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_SQL_Latin1_General_CP1_CI_AS WHERE Comments = N'kin_test1'
GO
_
最初のクエリはインデックスシークを実行できますが、暗黙的な変換を実行する必要がありますが、2番目のクエリはインデックススキャンを実行するため、大きなテーブルをスキャンする場合のパフォーマンスの点で非効率的です。
結論:
SQL_Latin1_General_CP1_CI_AS
_は、ユニコードと非ユニコードのデータを並べ替えることができるルールが異なるSQL照合です。Latin1_General_CI_AS
_は、ユニコードのデータと非ユニコードのデータを同じに並べ替えることができるルールを備えたWindows照合です。これにより、#tempテーブルで問題が発生しなくなりますが、落とし穴はありますか?
上記の私の答えを参照してください。
SQL 2008の "現在の"照合順序を使用しないと、機能や種類が失われますか?
それはすべて、あなたが参照している機能/機能に依存します。照合順序は、データの格納と並べ替えです。
2008年からSQL 2012に(たとえば2年間で)移動した場合はどうなりますか?それでは問題がありますか?ある時点で、Latin1_General_CI_ASに移動する必要がありますか?
カントバウチ!状況は変化する可能性があり、Microsoftの提案に沿っていると常に良いので、データと上記で述べた落とし穴を理解する必要があります。 this および this 接続アイテムも参照してください。
一部のDBAのスクリプトが完全なデータベースの行を完了し、新しい照合を使用してデータベースに挿入スクリプトを実行することを読みました-非常に怖くてこれに警戒しています-これを行うことをお勧めしますか?
照合順序を変更する場合は、このようなスクリプトが役立ちます。データベースの照合順序をサーバーの照合順序と一致するように何度も変更していることに気付き、それをうまく行うスクリプトをいくつか用意しました。必要な場合はお知らせください。
参照:
@ -Kinが answer で詳しく説明したものに加えて、サーバー(インスタンス)のデフォルトの照合を切り替えるときに注意すべきことがいくつかあります(水平線より上の項目は2つに直接関連しています)質問で言及された照合順序;水平線の下の項目は、一般に関連しています):
データベースのデフォルトのコレクションIS[〜#〜] NOT [〜#〜]CHANGINGの場合、「暗黙的な変換」のパフォーマンスの問題は、文字列リテラルとローカル変数はサーバーではなくデータベースのデフォルトの照合順序を使用するため、@ Kinの答えはでないが問題になるはずです。インスタンスレベルの照合順序が変更されるシナリオに対する唯一の影響ただし、データベースレベルの照合順序はありません(両方とも以下で詳しく説明します)。
これら2つの照合順序の違いの1つは、VARCHAR
データの特定の文字を並べ替える方法にあります(これはNVARCHAR
データには影響しません)。 EBCDIC以外のSQL_
照合順序は、VARCHAR
データに対して「文字列ソート」と呼ばれるものを使用しますが、他のすべての照合順序、およびEBCDIC以外のSQL_
照合順序に対してはNVARCHAR
データでさえ、「ワードソート」。違いは、「単語の並べ替え」では、ダッシュ-
とアポストロフィ'
(およびおそらく他のいくつかの文字?)の重みが非常に低く、文字列に他の違いがない限り基本的に無視されることです。この動作を実際に確認するには、次のコマンドを実行します。
DECLARE @Test TABLE (Col1 VARCHAR(10) NOT NULL);
INSERT INTO @Test VALUES ('aa');
INSERT INTO @Test VALUES ('ac');
INSERT INTO @Test VALUES ('ah');
INSERT INTO @Test VALUES ('am');
INSERT INTO @Test VALUES ('aka');
INSERT INTO @Test VALUES ('akc');
INSERT INTO @Test VALUES ('ar');
INSERT INTO @Test VALUES ('a-f');
INSERT INTO @Test VALUES ('a_e');
INSERT INTO @Test VALUES ('a''kb');
SELECT * FROM @Test ORDER BY [Col1] COLLATE SQL_Latin1_General_CP1_CI_AS;
-- "String Sort" puts all punctuation ahead of letters
SELECT * FROM @Test ORDER BY [Col1] COLLATE Latin1_General_100_CI_AS;
-- "Word Sort" mostly ignores dash and apostrophe
戻り値:
String Sort
-----------
a'kb
a-f
a_e
aa
ac
ah
aka
akc
am
ar
そして:
Word Sort
---------
a_e
aa
ac
a-f
ah
aka
a'kb
akc
am
ar
「文字列ソート」動作を「失う」ことになりますが、それを「機能」と呼ぶかどうかはわかりません。これは、望ましくないと見なされた動作です(Windows照合順序のいずれにも持ち込まれなかったという事実によって証明されています)。ただし、2つの照合順序間の動作の明確な違い(これも、EBCDIC以外のVARCHAR
データの場合のみ)であり、コードや「文字列ソート」動作に基づく顧客の期待。 これには、コードをテストし、場合によってはこの動作の変更がユーザーに悪影響を与える可能性があるかどうかを調査する必要があります。
SQL_Latin1_General_CP1_CI_AS
とLatin1_General_100_CI_AS
のもう1つの違いは、_VARCHAR
データ(NVARCHAR
dataは、SQL_
の処理など、ほとんどのæ
照合順序でこれらを実行できる) Expansions を実行する機能ですae
の場合:
IF ('æ' COLLATE SQL_Latin1_General_CP1_CI_AS =
'ae' COLLATE SQL_Latin1_General_CP1_CI_AS)
BEGIN
PRINT 'SQL_Latin1_General_CP1_CI_AS';
END;
IF ('æ' COLLATE Latin1_General_100_CI_AS =
'ae' COLLATE Latin1_General_100_CI_AS)
BEGIN
PRINT 'Latin1_General_100_CI_AS';
END;
戻り値:
Latin1_General_100_CI_AS
ここで「失われている」唯一のことは、これらの拡張を実行できないことができないことです。一般的に言えば、これはWindows照合に移行するもう1つの利点です。ただし、「文字列の並べ替え」から「単語の並べ替え」への移動と同じように、同じ注意が適用されます。これは、2つの照合順序間の動作の明確な違いです(ここでも、VARCHAR
データの場合のみ)。これらのマッピングを持つnotに基づいてコードおよび/または顧客の期待を持っている。 これには、コードをテストし、場合によってはこの動作の変更がユーザーに悪影響を与える可能性があるかどうかを調査する必要があります。
(@ZarephethによるこのS.O.の回答で最初に言及された: SQL Server SQL_Latin1_General_CP1_CI_ASをLatin1_General_CI_ASに安全に変換できますか? )
サーバーレベルの照合は、[model]
を含むシステムデータベースの照合を設定するために使用されます。 [model]
データベースは、サーバーを起動するたびに[tempdb]
を含む新しいデータベースを作成するためのテンプレートとして使用されます。ただし、サーバーレベルの照合順序を変更して[tempdb]
の照合順序を変更しても、CREATE #TempTable
が実行されたときに「現在」になっているデータベースと[tempdb]
の間の照合順序の違いを修正する簡単な方法があります。一時テーブルを作成するときは、COLLATE
句を使用して照合を宣言し、DATABASE_DEFAULT
の照合を指定します。
CREATE TABLE #Temp (Col1 NVARCHAR(40) COLLATE DATABASE_DEFAULT);
複数のバージョンが利用可能な場合は、目的の照合の最新バージョンを使用することをお勧めします。 SQL Server 2005以降、 "90"シリーズの照合順序が導入され、SQL Server 2008では "100"シリーズの照合順序が導入されました。これらの照合順序は、次のクエリを使用して見つけることができます。
SELECT * FROM sys.fn_helpcollations() WHERE [name] LIKE N'%[_]90[_]%'; -- 476
SELECT * FROM sys.fn_helpcollations() WHERE [name] LIKE N'%[_]100[_]%'; -- 2686
SQL Server 2008 R2を使用しているため、Latin1_General_100_CI_AS
ではなくLatin1_General_CI_AS
を使用する必要があります。
これらの特定の照合順序の大文字と小文字を区別するバージョン(つまり、SQL_Latin1_General_CP1_CS_AS
とLatin1_General_100_CS_AS
)の違いは、大文字と小文字を区別する並べ替えを行う場合の大文字と小文字の順序です。これは、LIKE
演算子およびPATINDEX
関数で使用できる単一文字のクラス範囲(つまり、[start-end]
)にも影響します。次の3つのクエリは、並べ替えと文字範囲の両方でこの効果を示しています。
SELECT tmp.col AS [Upper-case first]
FROM (VALUES ('a'), ('A'), ('b'), ('B'), ('c'), ('C')) tmp(col)
WHERE tmp.col LIKE '%[A-C]%' COLLATE SQL_Latin1_General_CP1_CS_AS
ORDER BY tmp.col COLLATE SQL_Latin1_General_CP1_CS_AS; -- Upper-case first
SELECT tmp.col AS [Lower-case first]
FROM (VALUES ('a'), ('A'), ('b'), ('B'), ('c'), ('C')) tmp(col)
WHERE tmp.col LIKE '%[A-C]%' COLLATE Latin1_General_100_CS_AS
ORDER BY tmp.col COLLATE Latin1_General_100_CS_AS; -- Lower-case first
SELECT tmp.col AS [Lower-case first]
FROM (VALUES (N'a'), (N'A'), (N'b'), (N'B'), (N'c'), (N'C')) tmp(col)
WHERE tmp.col LIKE N'%[A-C]%' COLLATE SQL_Latin1_General_CP1_CS_AS
ORDER BY tmp.col COLLATE SQL_Latin1_General_CP1_CS_AS; -- Lower-case first
小文字(同じ文字の場合)の前に大文字をソートする唯一の方法は、その動作をサポートする31の照合順序の1つを使用することです。これは、Hungarian_Technical_*
照合順序と、SQL_
の少数の照合順序(この動作のみをサポートする)です。 VARCHAR
データ用)。
この特定の変更についてはそれほど重要ではありませんが、サーバーをバイナリまたは大文字と小文字を区別する照合に変更すると影響があるため、サーバーレベルの照合も以下に影響するということを知っておくとよいでしょう。
sysname
データ型の名前解決
つまり、すべての不良コードの責任があると思われるあなたまたは「最近去ったプログラマ」;-)が大文字小文字を区別せず、変数を@SomethingID
として宣言したが、後で@somethingId
として参照した場合、大文字と小文字を区別する照合またはバイナリ照合に移動すると、破損します。同様に、sysname
データ型を使用しているが、それをSYSNAME
、SysName
、またはすべて小文字以外のものとして参照しているコードも、大文字と小文字を区別する照合またはバイナリ照合。