文字列比較で大文字と小文字を区別するために、データベース照合をLatin1_General_BIN
に設定しました。これはパフォーマンスに影響を与えますか?データベースのDMLまたはDDL操作に影響がありますか?データベースが既に存在し、テーブルが含まれています。
SQL Serverの照合順序 文字データの照合とソートのルールを決定します。通常、比較セマンティクスとデータのコンシューマーが必要とするソート順に基づいて、最初に照合を選択します。
通常、人間は binary collations が期待するソートおよび比較動作を生成することを認識していません。したがって、これらは最高のパフォーマンス(特に、純粋なコードポイントBIN2バージョン)を提供しますが、ほとんどの実装ではそれらを使用しません。
次に、生のパフォーマンス用語(ただし、非Unicode文字列のみ)には、下位互換性 SQL照合順序 があります。 Unicodeデータを使用する場合、これらの照合順序は同じパフォーマンス特性を持つ Windows collation を代わりに使用します。ここには微妙なトラップがあるため、SQL照合を最近選択する十分な理由が必要です(米国のシステムで作業している場合を除いて、それがデフォルトのままです)。
Windowsの照合順序は、Unicodeの比較と並べ替えの規則が複雑なため、一般的に最も遅くなります。それにもかかわらず、これらはSQL ServerのWindowsとの完全な互換性を提供し、Unicode標準の変更に対応するために定期的に維持されます。 Unicodeデータを含む最近の使用では、Windows照合が一般的に推奨されます。
TL; DR
必要なのは大文字と小文字を区別する比較と並べ替えのセマンティクスだけである場合は、いずれかのベース照合の_CS_
(大文字と小文字を区別)のバリエーションを選択する必要がありますユーザーの言語と文化に期待される動作を提供します。たとえば、どちらも大文字と小文字が区別される照合順序です。
-- Latin1-General, case-sensitive, accent-sensitive
Latin1_General_CS_AS
-- Latin1-General, case-sensitive, accent-sensitive for Unicode Data,
-- SQL Server Sort Order 51 on Code Page 1252 for non-Unicode Data
SQL_Latin1_General_CP1_CS_AS
これらの定義は sys.fn_helpcollations を使用して確認できます
照合順序以外はまったく同じである4つのテーブル。 1つのバイナリ、1つの大文字と小文字を区別、1つの大文字と小文字を区別、1つのSQLで大文字と小文字を区別:
CREATE TABLE #Example_BIN
(
string nvarchar(50)
COLLATE Latin1_General_BIN
NOT NULL
);
CREATE TABLE #Example_CS
(
string nvarchar(50)
COLLATE Latin1_General_CS_AI
NOT NULL
);
CREATE TABLE #Example_CI
(
string nvarchar(50)
COLLATE Latin1_General_CI_AI
NOT NULL
);
CREATE TABLE #Example_SQL
(
string varchar(50) -- Note varchar
COLLATE SQL_Latin1_General_CP1_CS_AS
NOT NULL
);
各テーブルで同じサンプルデータ:
INSERT #Example_BIN
(string)
VALUES
(N'A'),
(N'a'),
(N'B'),
(N'b'),
(N'C'),
(N'c');
INSERT #Example_CS
SELECT EB.string
FROM #Example_BIN AS EB;
INSERT #Example_CI
SELECT EB.string
FROM #Example_BIN AS EB;
INSERT #Example_SQL
SELECT EB.string
FROM #Example_BIN AS EB;
ここで、 'a'より大きいストリングを検索します。
SELECT EB.string AS BIN
FROM #Example_BIN AS EB
WHERE EB.string > N'a'
ORDER BY EB.string;
SELECT EC.string AS CS
FROM #Example_CS AS EC
WHERE EC.string > N'a'
ORDER BY EC.string;
SELECT EC2.string AS CI
FROM #Example_CI AS EC2
WHERE EC2.string > N'a'
ORDER BY EC2.string;
SELECT ES.string AS SQL
FROM #Example_SQL AS ES
WHERE ES.string > 'a' -- not Unicode
ORDER BY ES.string;
╔═════╗
║ BIN ║
╠═════╣
║ b ║
║ c ║
╚═════╝
╔════╗
║ CS ║
╠════╣
║ A ║
║ b ║
║ B ║
║ c ║
║ C ║
╚════╝
╔════╗
║ CI ║
╠════╣
║ B ║
║ b ║
║ C ║
║ c ║
╚════╝
╔═════╗
║ SQL ║
╠═════╣
║ B ║
║ b ║
║ C ║
║ c ║
╚═════╝
ただし、SQL照合でUnicodeリテラルを使用する場合、暗黙的な変換規則によりWindows照合比較が行われます。
SELECT ES.string AS SQL
FROM #Example_SQL AS ES
WHERE ES.string > N'a'
ORDER BY ES.string;
...そしてSQL照合結果change:
╔═════╗
║ SQL ║
╠═════╣
║ A ║
║ B ║
║ b ║
║ C ║
║ c ║
╚═════╝
これは、すでにテーブルが定義されている既存のデータベースであることを考えると、DML操作に対する潜在的なパフォーマンスの影響を超えて、データベースの照合順序を変更するアクションには、いくつかの非常に深刻な影響があります(実際にはすでにそこにありました)。パフォーマンスと機能には非常に実際の影響があり、この変更は意図した目標を達成しなかっただけでなく(少なくとも一貫してではない)、次の点で動作を変更した(または新しいテーブルが作成されたときの動作を変更した)データの順序付けと同等化の方法。
Paulはすでに、回答のさまざまな種類の照合順序間のパフォーマンスと動作の違いについて、適切な説明と例を提供しているので、ここでは繰り返しません。ただし、いくつかのポイントには追加の詳細が必要です。また、新しいDBの照合順序を設定するのではなく、既存のDBの照合順序を変更するという現在のシナリオに関連して追加するポイントがいくつかあります。
バイナリ照合順序は、大文字と小文字を区別するだけではありません。すべてを区別します!したがって、バイナリ照合(__BIN
_または__BIN2
_で終わる)を使用することにより、比較もアクセントに敏感、かなに敏感、幅に敏感になり、グルテンに敏感になる可能性があります(少なくとも傾向のようです)最近 ;-) )。これは、この変更を行うことによる望ましい影響でしたか?エンドユーザーはこの行動の変化を期待していますか?
照合順序は、比較だけでなく並べ替えにも影響します。バイナリ照合は、それぞれのASCII
またはUNICODE
バイト値(それぞれVARCHAR
またはNVARCHAR
に依存)に基づいてソートしますbyte。したがって、バイナリ照合を選択することで、言語(/ =文化)に固有の重み付けルールをあきらめ、各文字(次のような一部の言語の文字も)ハンガリー語。2文字で構成されています)。したがって、 "ch"がafter "k"の後に自然に来る場合、それはバイナリ照合を使用して発生することはありません。繰り返しますが、これはこの変更を行うことの望ましい影響でしたか?エンドユーザーはこの行動の変化を期待していますか?
アプリケーションに特定の下位互換性要件がない限り、BIN
照合順序の代わりに_BIN2
_照合順序を使用する必要があります。もちろん、最初にバイナリ照合順序が必要であると想定します。 _BIN2
_照合はSQL Server 2005で導入され、MSDNページによると BINおよびBIN2照合を使用するためのガイドライン :
"_BIN"で終わるSQL Serverの以前のバイナリ照合順序は、Unicodeデータに対して不完全なコードポイント間コード比較を実行していました。古いSQL Serverのバイナリ照合順序では、最初の文字をWCHARとして比較し、その後にバイトごとの比較を行いました。
...
[_BIN2]バイナリ照合順序に移行して、真のコードポイント比較を利用できます。新しいアプリケーションの開発には、新しいバイナリ照合順序を使用する必要があります。
また、__BIN2
_照合順序は StringComparison Enumeration のOrdinal
オプションの動作と便利に一致するため、それを使用して.NETコードで比較と並べ替えが行われることにも注意してください。オプションは、SQL Server内で実行される同じ操作と同じ結果になります(もちろん、__BIN2
_照合順序を使用する場合)。
__BIN2
_照合順序について述べたのと同様の理由で、下位互換性動作を維持するための特定の要件がない限り、SQL Server固有の照合順序(つまり、照合順序)ではなく、Windows照合順序を使用するようにしてください。 _SQL_
_で始まるものは、今では「だらしない」と見なされます;-))。
Unicodeデータ(つまり、N
が前に付いた文字列、またはデータ型がNChar
またはNVarChar
として指定されているアプリのコードからSQL Serverに入る)を使用している場合、表示されません。ある照合と別の照合を使用すると、NCHAR
またはNVARCHAR
文字列フィールドの挿入または更新に違いが生じます。
非Unicodeデータを使用する場合、または非Unicodeフィールドに挿入または更新する場合、特定の照合(データベースまたはフィールド)mightは、挿入される文字がある場合に小さな役割を果たします/照合によって定義されているコードページで指定されているように、更新されたものは翻訳する必要があるか、マップできない(単語でさえあるか?)もちろん、この潜在的な問題は、非Unicodeデータまたはデータ型を使用している場合に必ず発生し、DB照合順序を変更するこのシナリオに固有のものではありません。この変更は文字列リテラルに影響します(DB照合がフィールドの照合と異なる場合、これは既に問題であった可能性があります)。ただし、DB照合順序に変更が加えられていない場合でも、他のDBから、またはSQL Serverの外部(任意のクライアントコード)から受信するデータには、任意の文字を含めることができ、特定のエンコーディングにすることができます。
非常に重要!!!データベースのデフォルトの照合を変更すると、既存のテーブルの既存の文字列フィールドに指定された照合がになります。 notは変更されますが、すべてのnewフィールドには、データベースのデフォルトの照合順序があります(COLLATE
句でオーバーライドされない限り)。これは、3つの方法でクエリに影響を与えます。
1)これらの既存のフィールドのいずれかで新しいフィールドのいずれかにJOINをクエリすると、照合不一致エラーが発生します。
_USE [master];
GO
IF (DB_ID(N'ChangeCollationTest') IS NOT NULL)
BEGIN
PRINT 'Dropping [ChangeCollationTest] DB...';
ALTER DATABASE [ChangeCollationTest]
SET SINGLE_USER
WITH ROLLBACK IMMEDIATE;
DROP DATABASE [ChangeCollationTest];
END;
GO
PRINT 'Creating [ChangeCollationTest] DB...';
CREATE DATABASE [ChangeCollationTest]
COLLATE SQL_Latin1_General_CP1_CI_AS;
GO
USE [ChangeCollationTest];
GO
CREATE TABLE [CollateTest-SQL_Latin1_General_CP1_CI_AS]
(Col1 NVARCHAR(50) COLLATE DATABASE_DEFAULT, Col2 NVARCHAR(50));
SELECT *
FROM sys.columns sc
WHERE sc.[object_id] = OBJECT_ID(N'[CollateTest-SQL_Latin1_General_CP1_CI_AS]');
-- "collation_name" for both fields shows: SQL_Latin1_General_CP1_CI_AS
GO
USE [master];
GO
ALTER DATABASE [ChangeCollationTest]
COLLATE Latin1_General_BIN2;
GO
USE [ChangeCollationTest];
GO
CREATE TABLE [CollateTest-Latin1_General_BIN2]
(Col1 NVARCHAR(50) COLLATE DATABASE_DEFAULT, Col2 NVARCHAR(50));
SELECT *
FROM sys.columns sc
WHERE sc.[object_id] = OBJECT_ID(N'[CollateTest-Latin1_General_BIN2]');
-- "collation_name" for both fields shows: Latin1_General_BIN2
GO
SELECT *
FROM dbo.[CollateTest-SQL_Latin1_General_CP1_CI_AS] ctSQL
INNER JOIN dbo.[CollateTest-Latin1_General_BIN2] ctWIN
ON ctWIN.Col1 = ctSQL.Col1;
_
戻り値:
_Msg 468, Level 16, State 9, Line 4
Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and
"Latin1_General_BIN2" in the equal to operation.
_
2)文字列リテラルまたは変数と比較する既存のテーブルの既存のフィールド(前のデフォルト照合に設定)の述語/フィルターはエラーになりませんが、 SQL Serverは両側の照合を同等にする必要があり、文字列リテラルまたは変数をフィールドの照合に自動的に変換するため、パフォーマンスに影響を与える可能性があります。 [実際の実行プランを含める](Control-M)を有効にしてから、次のコマンドを実行します(上記のクエリをすでに実行していると想定)。
_SELECT *
FROM dbo.[CollateTest-SQL_Latin1_General_CP1_CI_AS] ctSQL
WHERE ctSQL.Col1 = N'a';
-- Unspecified collations on string literals and variables assume the database default
-- collation. This mismatch doesn't cause an error because SQL Server adds a
-- "[Col1]=CONVERT_IMPLICIT(nvarchar(4000),[@1],0)" but it can hurt performance.
SELECT *
FROM dbo.[CollateTest-Latin1_General_BIN2] ctWIN
WHERE ctWIN.Col1 = N'a';
-- No CONVERT_IMPLICIT; plan shows "[Col1]=[@1]".
_
3)さらに、暗黙的な変換について言えば、それが文字列リテラルであることに注意してください(データベースのデフォルト照合の暗黙の照合を使用:_Latin1_General_BIN2
_ )変換されますが、テーブルのフィールドはではありません。このフィルターが大文字と小文字を区別しない(古い照合)か、大文字と小文字を区別する(新しい照合)かどうかについての推測はありますか?次を実行して確認します。
_INSERT INTO dbo.[CollateTest-SQL_Latin1_General_CP1_CI_AS] (Col1)
VALUES (N'a'), (N'A');
SELECT ctSQL.Col1
FROM dbo.[CollateTest-SQL_Latin1_General_CP1_CI_AS] ctSQL
WHERE ctSQL.Col1 = N'a';
_
戻り値:
_Col1
----
a
A
_
やった! CONVERT_IMPLICIT()
が原因で、このクエリのパフォーマンスにわずかな(または多分より重要な)ヒットがあるだけでなく、必要な大文字と小文字を区別する方法でも動作しません。
エルゴ、既にテーブルがあるDBで照合順序が変更された場合、はい、パフォーマンスと機能の両方が影響を受けます。
照合が新しいDBで設定されている場合、Paulはバイナリ照合がどのように高速であるかを説明することですでにそれをカバーしていますが、おそらく期待または希望する方法でソートされません。
また、条件ごとに常に照合を指定できることにも注意してください。 [〜#〜] collate [〜#〜] 句は、WHERE
条件、_ORDER BY
_、および文字列を受け入れるほとんどすべての場所に追加できます。
例1(WHERE条件):
_SELECT tmp.col AS [SQL-CaseSensitive]
FROM (VALUES ('a'), ('A'), ('b'), ('B')) tmp(col)
WHERE tmp.col > 'a' COLLATE SQL_Latin1_General_CP1_CS_AS;
SELECT tmp.col AS [Windows-CaseSensitive]
FROM (VALUES ('a'), ('A'), ('b'), ('B')) tmp(col)
WHERE tmp.col > 'a' COLLATE Latin1_General_CS_AI;
_
戻り値:
_SQL-CaseSensitive
-----------------
b
B
Windows-CaseSensitive
-----------------
A
b
B
_
例2(ORDER BY):
_SELECT tmp.col AS [Windows-CaseSensitive]
FROM (VALUES ('a'), ('A'), ('b'), ('B')) tmp(col)
ORDER BY tmp.col COLLATE Latin1_General_CS_AI;
SELECT tmp.col AS [Windows-Binary]
FROM (VALUES ('a'), ('A'), ('b'), ('B')) tmp(col)
ORDER BY tmp.col COLLATE Latin1_General_BIN2;
_
戻り値:
_Windows-CaseSensitive
-----------------
a
A
b
B
Windows-Binary
-----------------
A
B
a
b
_
例3(IFステートメント):
_IF ('A' = 'a') SELECT 1 AS [DatabaseDefault-CaseInsensitive?];
-- if the DB is not case-sensitive or binary, returns 1
IF ('A' = 'a' COLLATE Latin1_General_BIN2) SELECT 2 AS [Windows-Binary];
_
戻り値:
_DatabaseDefault-CaseInsensitive?
--------------------------------
1
{nothing}
_
例4(関数入力パラメーターに関連付ける):
_SELECT UNICODE(N'????') AS [UCS-2],
UNICODE(N'????' COLLATE Latin1_General_100_CI_AS_SC) AS [UTF-16];
-- This character is a Unicode supplemental character and is not part of the
-- default UCS-2 encoding. In order for built-in functions to handle these
-- characters correctly, either the DB default collation needs to end in
-- "_SC" (available as of SQL Server 2012), or use as shown here.
-- See the character in more detail here: http://unicode-table.com/en/1F0A1/
_
戻り値:
_UCS-2 UTF-16
------ -------
55356 127137
_
55,356のUCS-2値は、「サロゲートペア」の2つの値の最初の値であるという点で部分的に正しいです。ただし、__SC
_照合を明示的に指定しない限り、UNICODE()
関数は各文字を2バイト値としてのみ認識でき、2バイトのサロゲートペアを適切に処理する方法がわかりません。
[〜#〜]更新[〜#〜]
上記のすべての例を使用しても、通常見過ごされ、バイナリ比較/照合で否定される大文字と小文字を区別する比較の1つの側面は、Unicodeの一部である正規化(合成と分解)です。
例5(バイナリ比較がでない場合大文字と小文字が区別されます):
大文字と小文字が区別される真の比較では、別の文字と組み合わせて、別のUnicodeコードポイントとして既に存在する別の文字を形成する文字を組み合わせることができます。大文字と小文字を区別する比較では、表示可能な文字が考慮されますが、作成に使用されたコードポイントは考慮されません。
_SELECT 'Equal' AS [Binary],
NCHAR(0x00FC) AS [ü],
N'u' + NCHAR(0x0308) AS [u + combining diaeresis]
WHERE NCHAR(0x00FC) COLLATE Latin1_General_100_BIN2
= N'u' + NCHAR(0x0308) COLLATE Latin1_General_100_BIN2
-- No result as they are a different number of code points,
-- as well as being different code points.
SELECT 'Equal' AS [Case-Sensitive],
NCHAR(0x00FC) AS [ü],
N'u' + NCHAR(0x0308) AS [u + combining diaeresis]
WHERE NCHAR(0x00FC) COLLATE Latin1_General_100_CS_AS -- ü
= N'u' + NCHAR(0x0308) COLLATE Latin1_General_100_CS_AS -- u + combining diaeresis
-- Result set returned, even being a different number of code points AND Accent Sensitive,
-- due to normalization
_
戻り値:
_Binary ü u + combining diaeresis
------- --- -------------------------
{nothing}
Case-Sensitive ü u + combining diaeresis
--------------- --- -------------------------
Equal ü ü
_
大文字と小文字を区別する真の比較では、ワイド文字をワイド以外の文字と同等にすることもできます。
_IF (N'sofia' = N'sofia' COLLATE Latin1_General_100_BIN2)
SELECT 'Values are the same' AS [Binary]
ELSE
SELECT 'Values are different' AS [Binary];
IF (N'sofia' = N'sofia' COLLATE Latin1_General_100_CS_AS)
SELECT 'Values are the same' AS [Case-Sensitive]
ELSE
SELECT 'Values are different' AS [Case-Sensitive];
_
戻り値:
_Binary
---------------
Values are different
Case-Sensitive
---------------
Values are the same
_
_BIN
_および__BIN2
_)照合順序はではありません大文字と小文字を区別します!