SQL 2005 [SQL_Latin1_General_CP1_CI_AS]から2008への移行-「後方互換性」を使用して機能を失う


18

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です。例外的な問題が発生しました- 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

  1. これにより、#tempテーブルで問題が発生することはなくなりますが、落とし穴はありますか?

  2. SQL 2008の「現在の」照合を使用しないことにより、あらゆる種類の機能または機能が失われますか?

  3. 2008年からSQL 2012に移行したとき(2年以内など)はどうですか?問題はありますか?
  4. ある時点で行くことを余儀なくされLatin1_General_CI_ASますか?

  5. 一部のDBAのスクリプトが完全なデータベースの行を完了し、新しい照合を使用してデータベースに挿入スクリプトを実行することを読みました。


2
SQL Server 2014でHekatonを使用する可能性があると思われる場合は、以下を参照してください
アーロンバートランド

回答:


20

まず第一に、照合、ソート順、コードページなどの用語について人々が話すとき、まだ多くの混乱があると感じているので、このような長い答えをおologiesびします。

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

---これには暗黙の変換はありません

ここに画像の説明を入力してください

暗黙的な変換の理由は、データベース照合とサーバー照合の両方がSQL_Latin1_General_CP1_CI_ASあり、テーブルTable_Latin1_General_CI_ASに列コメントが定義されVARCHAR(50)ているためです COLLATE Latin1_General_CI_ASのようにSQL Serverが暗黙の型変換を行う必要があり、ルックアップ中に、。

テスト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照合です。
  • SQL照合は、nvarcharデータとvarcharデータを比較するときにインデックススキャンを行い、シークしないという上記のテストで見られるように、ユニコードデータと非ユニコードデータを比較するときにインデックスを使用できません。
  • Latin1_General_CI_AS は、ユニコードと非ユニコードが同じであるためにデータをソートできるようにするルールを備えたWindows照合です。
  • Windows照合では、ユニコードデータと非ユニコードデータを比較するときに、引き続きインデックス(上記の例ではインデックスシーク)を使用できますが、パフォーマンスが若干低下します。
  • Erland Sommarskogの回答+彼が指摘した接続項目を読むことを強くお勧めします。

これにより、#tempテーブルで問題が発生することはなくなりますが、落とし穴はありますか?

上記の私の答えをご覧ください。

SQL 2008の「現在の」照合を使用しないことにより、あらゆる種類の機能または機能が失われますか?

それはすべて、参照している機能/機能に依存します。照合とは、データの保存と並べ替えです。

2008年からSQL 2012に移行したとき(2年以内など)はどうですか?問題はありますか?ある時点で、Latin1_General_CI_ASに行くことを強制されますか?

カントバウチ!状況が変化する可能性があり、Microsoftの提案に沿っていることは常に良いことであるため、上記のデータと落とし穴を理解する必要があります。これこの接続項目も参照しください。

一部のDBAのスクリプトが完全なデータベースの行を完了し、新しい照合を使用してデータベースに挿入スクリプトを実行することを読みました。

照合順序を変更する場合、このようなスクリプトは便利です。サーバーの照合に一致するようにデータベースの照合を何度も変更していることがわかりました。必要な場合はお知らせください。

参考文献:


5

@Kinの回答で詳述したことに加えて、サーバーの(つまり、インスタンスの)デフォルトの照合を切り替えるときに注意すべき点がいくつかあります(水平線より上の項目は、質問で言及された2つの照合に直接関連しています;項目水平線の下は一般に関連しています):

  • データベースのデフォルトの収集が変更されない場合、@ Kinの回答で説明されている「暗黙的な変換」パフォーマンスの問題はでない文字列リテラルとローカル変数は、データベースのデフォルトの照合順序ではなく、サーバーのを使用するので問題になります。インスタンスレベルの照合が変更され、データベースレベルの照合は変更されないシナリオへの唯一の影響は次のとおりです(以下で詳細に説明します)。

    • 潜在的な照合は、一時テーブルと競合します(テーブル変数は競合しません)。
    • 変数やカーソルの大文字と小文字が宣言と一致しない場合に潜在的な破損コード(ただし、これはバイナリまたは大文字と小文字を区別する照合を使用してインスタンスに移動する場合にのみ発生します)。
  • これら2つの照合順序の1つの違いは、VARCHARデータの特定の文字を並べ替える方法です(これはNVARCHARデータに影響しません)。非EBCDIC SQL_照合はVARCHARデータに「文字列ソート」と呼ばれるものを使用しますが、他のすべての照合、さらにNVARCHARは非EBCDIC SQL_照合にデータも「ワードソート」と呼ばれるものを使用します。違いは、「単語の並べ替え」では、ダッシュ-とアポストロフィ'(および他のいくつかの文字)に非常に低い重みが与えられ、文字列に他の違いがない限り本質的に無視されることです。この動作を実際に確認するには、次を実行します。

    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_ASLatin1_General_100_CI_AS行う能力である拡張をVARCHAR(データNVARCHARデータはすでにほとんどのため、これらの操作を行うことができSQL_、このような処理など、照合順序)、æそれはあたかも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データのみ)。これらのマッピングがないことに基づく期待。これには、コードをテストし、この動作の変更がユーザーに悪影響を与える可能性があるかどうかを調査する必要があります。

    (このSOの回答で最初に指摘された@Zarepheth: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_ASLatin1_General_100_CS_AS)の違いは、大文字と小文字を区別する並べ替えを行うときの大文字と小文字の順序です。これ[start-end]は、LIKE演算子とPATINDEX関数で使用できる単一文字クラス範囲()にも影響します。次の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の照合順序のいずれかを使用することであるということですサポートされていることを行動、Hungarian_Technical_*照合順序の一握りSQL_だけのために、この動作をサポート照合順序(VARCHARデータを)。

  • この特定の変更ではそれほど重要ではありませんが、サーバーをバイナリ照合または大文字と小文字を区別する照合に変更すると影響を受けるため、知っておくと良いのは、サーバーレベルの照合も影響することです。

    • ローカル変数名
    • カーソル名
    • GOTOラベル
    • sysnameデータ型の名前解決


    つまり、あなたまたは「最近去ったプログラマー」がすべての悪いコードに責任があるようです;-) 大文字と小文字を区別せずに変数を宣言しました@SomethingIDが、@somethingId後でそれを参照した場合、ケースに移動すると壊れます機密またはバイナリ照合。同様に、使用するコードsysnameデータ型が、としてそれを指しSYSNAMESysName大文字と小文字を区別またはバイナリ照合を使用してインスタンスに移動した場合、またはすべて小文字以外にも破損します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.