Veritabanı varsayılan harmanlamasını değiştirirken Latin1_Genel_BIN performans etkisi


16

Ben Latin1_General_BINdize karşılaştırmaları büyük / küçük harfe duyarlı hale getirmek için veritabanı harmanlama ayarladım . Bunun performans üzerinde bir etkisi olacak mı? Veritabanındaki DML veya DDL işlemleri üzerinde herhangi bir etkisi olacak mı? Veritabanı zaten içindeki tablolarla var.

Yanıtlar:


24

SQL Server'daki harmanlamalar karakter verilerini eşleştirme ve sıralama kurallarını belirler. Normalde, önce karşılaştırma semantiği ve tüketicilerin ihtiyaç duyduğu sıralama düzenine dayalı bir harmanlama seçersiniz.

İnsanlar genellikle ikili harmanlamaların bekledikleri sıralama ve karşılaştırma davranışlarını ürettiğini görmezler. Bu nedenle, bunlar en iyi performansı sunsa da (özellikle saf kod noktası BIN2 sürümleri) çoğu uygulama bunları kullanmaz.

Ham performans terimlerinden sonraki (yalnızca Unicode olmayan dizeler için) geriye dönük uyumluluk SQL harmanlamalarıdır . Unicode verileriyle çalışırken, bu harmanlamalar aynı performans özelliklerine sahip bir Windows harmanlaması kullanır. Burada ince tuzaklar var, bu yüzden bu günlerde bir SQL harmanlaması seçmek için iyi nedenlere ihtiyacınız var (hala varsayılan olan bir ABD sisteminde çalışmadığı sürece).

Windows harmanlamaları, genel olarak, karmaşık Unicode karşılaştırma ve sıralama kuralları nedeniyle en yavaş olanlardır. Bununla birlikte, bunlar SQL Server'da Windows ile tam uyumluluk sağlar ve Unicode standardındaki değişikliklere ayak uydurmak için düzenli olarak korunur. Unicode verilerini içeren modern kullanım için genellikle bir Windows harmanlaması önerilir.

TL; DR

İstediğiniz tek şey büyük / küçük harfe duyarlı karşılaştırma ve sıralama semantiği ise, _CS_hangi temel harmanlamanın kullanıcılarınızın dili ve kültürü için beklenen davranışı sağladığı (Büyük / Küçük Harfe Duyarlı için) varyasyonunu seçmelisiniz . Örneğin, her ikisi de büyük / küçük harfe duyarlı harmanlamalardır:

-- 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

Bu tanımları sys.fn_helpcollations kullanarak görebilirsiniz

Örnekler

Harmanlama dışında tamamen aynı olan dört tablo ; bir ikili, bir büyük / küçük harf duyarlı, bir büyük / küçük harf duyarsız ve bir SQL büyük / küçük harfe duyarlı:

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
);

Her tablo için aynı örnek veriler :

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;

Şimdi ' a'dan büyük dizeler bulmak istiyoruz :

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;

Sonuçlar:

╔═════╗
 BIN 
╠═════╣
 b   
 c   
╚═════╝

╔════╗
 CS 
╠════╣
 A  
 b  
 B  
 c  
 C  
╚════╝

╔════╗
 CI 
╠════╣
 B  
 b  
 C  
 c  
╚════╝

╔═════╗
 SQL 
╠═════╣
 B   
 b   
 C   
 c   
╚═════╝

En sonunda...

Bununla birlikte, SQL harmanlama ile bir Unicode değişmezi kullanırsak, örtük dönüştürme kuralları bir Windows harmanlama karşılaştırmasıyla sonuçlanır:

SELECT ES.string AS SQL
FROM #Example_SQL AS ES
WHERE ES.string > N'a'
ORDER BY ES.string;

... ve SQL harmanlama sonuçları değişir :

╔═════╗
 SQL 
╠═════╣
 A   
 B   
 b   
 C   
 c   
╚═════╝

10

Bunun zaten tabloları tanımlanmış mevcut bir veritabanı olduğu göz önüne alındığında , veritabanı harmanlamasını değiştirme eyleminin, DML işlemlerine (aslında zaten orada olan) olası performans etkisinin ötesinde bazı ciddi etkileri vardır. Performans ve işlevsellik üzerinde çok gerçek bir etkisi vardır ve bu değişiklik sadece amaçlanan hedefe ulaşmakla kalmadı (en azından tutarlı bir şekilde değil), aynı zamanda davranışı büyük olasılıkla değiştirdi (veya yeni tablolar oluşturulduğunda davranışı değiştirecek). verinin nasıl sıralandığı ve denkleştirildiği.

Paul zaten cevabındaki farklı harmanlama türleri arasındaki performans ve davranış farklılıklarının iyi bir açıklamasını ve örneklerini verdi, bu yüzden burada tekrar etmeyeceğim. Bununla birlikte, birkaç noktanın ek ayrıntıya ihtiyacı vardır ve yeni bir DB'nin harmanlanmasını ayarlamak yerine mevcut bir DB'nin harmanlamasını değiştirme senaryosuna ilişkin eklenmesi gereken birkaç nokta daha vardır.

  1. İkili harmanlamalar, büyük / küçük harfe duyarlı değildir; her şey hassastır! Dolayısıyla, ikili bir harmanlama kullanarak ( _BINveya ile biten _BIN2), karşılaştırmalarınız artık aksan duyarlı, kana duyarlı, genişliğe duyarlı ve potansiyel olarak glutene duyarlı (en azından bu günlerde trend gibi görünüyor ;-)). Bu, bu değişikliği yapmanın istenen etkisi miydi? Son kullanıcılar bu davranış değişikliğini bekliyorlar mı?

  2. Harmanlamalar sadece karşılaştırmaları değil sıralamayı da etkiler. İkili harmanlama , her baytınASCII veya UNICODEbayt değerine ( sırasıyla VARCHARveya NVARCHARsırasıyla) göre sıralanır . Bu nedenle, ikili bir harmanlama seçerek , o kültürün alfabesine göre her bir karakteri (Macarca gibi bazı dillerdeki 2 harften oluşan karakterler) sıralayan dile / kültüre özgü ağırlıklandırma kurallarından vazgeçmiş olursunuz . Yani, eğer "ch" doğal olarak "k" den sonra gelirse , bu ikili bir harmanlama kullanılmayacaktır. Yine bu, bu değişikliği yapmanın istenen etkisi miydi? Son kullanıcılar bu davranış değişikliğini bekliyorlar mı?

  3. Uygulamanız için belirli geriye dönük uyumluluk gereksinimleriniz olmadığı sürece , elbette, ilk etapta ikili bir harmanlama istediğinizi varsayarak, harmanlama BIN2yerine kullanmalısınız BIN. BIN2Alfabe, SQL Server 2005'te sunulan ve MSDN sayfaya göre edildi BIN ve BIN2 harmanlamalar kullanma Rehberi :

    SQL Server'da önceki "_BIN" ile biten ikili harmanlamalar, Unicode verileri için eksik bir kod-kod-nokta karşılaştırması gerçekleştirdi. Eski SQL Server ikili harmanlamaları, ilk karakteri WCHAR, ardından bayt-byte karşılaştırması ile karşılaştırdı.

    ...

    Gerçek kod noktası karşılaştırmalarından yararlanmak için [_BIN2] ikili harmanlamalarına geçebilirsiniz ve yeni uygulamaların geliştirilmesi için yeni ikili harmanlamaları kullanmalısınız.

    Ayrıca, _BIN2harmanlamaların, bu Ordinalseçeneği kullanarak .NET kodunda yapılan karşılaştırmalar ve sıralamaların SQL Server'da gerçekleştirilen işlemlerle aynı sonuçları vereceği şekilde , StringComparison Numaralandırma seçeneğinin davranışıyla uygun şekilde eşleştiğine dikkat edilmelidir. _BIN2alfabe, tabii ki).

  4. _BIN2Harmanlamalarla ilgili olarak henüz belirtilmiş olanlara benzer nedenlerle , geriye dönük uyumluluk davranışını sürdürmek için özel gereksinimleriniz yoksa, SQL Server'a özgü harmanlamaları değil, Windows harmanlamalarını kullanmaya eğilimli olmalısınız (yani, SQL_şimdi başlayanlar dikkate alınır) tür "sucky" ;-)).

  5. Unicode verileri (yani N, veri türünün NCharveya olarak belirtildiği uygulama kodundan SQL Server ile ön ekli veya SQL Server'a gelen dize NVarChar) kullanırken, bir harmanlama ile diğerinin kullanılmasının bir NCHARveya NVARCHARdize alanı eklemek veya güncellemek için nasıl bir fark yaratacağını görmüyorum .

    Unicode olmayan veriler kullanılarak, ya içine yerleştirirken veya bir Unicode olmayan alanını ardından belli harmanlama (veritabanı veya alan) güncellerken olabilir olduğu (Çevrilecek herhangi karakterler yerleştirilmeden eğer / güncellenmiş ihtiyaç küçük bir rol oynamaktadır veya haritalanabilir değildir bir kelime bile?), harmanlama tarafından tanımlanan Kod Sayfası tarafından belirtildiği gibi. Tabii ki, bu olası sorun Unicode olmayan veri veya veri türlerini her kullandığında ortaya çıkar ve DB harmanlamasını değiştirme senaryosuna özgü değildir. Bu değişiklik dize değişmezlerini etkileyecektir (DB harmanlaması alanın harmanlamasından farklıysa zaten bir sorun olabilir). Ancak, DB harmanlamasında hiçbir değişiklik yapılmasa bile, diğer DB'lerden veya SQL Server dışından (herhangi bir istemci kodu) gelen veriler herhangi bir karakter içerebilir ve herhangi bir kodlamaya sahip olabilir.

  6. ÇOK ÖNEMLİ!!! Veritabanı varsayılan harmanlama değiştirirken, harmanlama olacak varolan herhangi tablolarda varolan herhangi bir dize alanları için belirtilen değil değiştirmek, ancak herhangi bir yeni (aracılığıyla geçersiz sürece alanları veritabanı varsayılan bir harmanlama olacak COLLATEfıkra). Bu, sorgularınızı üç şekilde etkileyecektir:

    1) Herhangi bir sorgu mevcut alanlardan herhangi birinde yeni alanlardan birine katılırsa, bir harmanlama uyuşmazlığı hatası alırsınız:

    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;

    İadeler:

    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) Dize değişmezleri veya değişkenleri ile karşılaştırıldığında var olan tabloların (önceki varsayılan harmanlama olarak ayarlanmış) mevcut alanlarındaki hataları tahmin etmez / filtreler hata vermez, ancak SQL Server'ın harmanlamasını eşitlemesi gerektiğinden kesinlikle etkilenebilir her iki tarafı da otomatik olarak dize hazır bilgisi veya değişkeni alanın harmanlamasına dönüştürür. "Gerçek Yürütme Planını Dahil Et" (Control-M) seçeneğini etkinleştirin ve ardından aşağıdakileri yürütün (yukarıda gösterilen sorguları zaten çalıştırdığınız varsayılarak):

    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) VE, örtük dönüşümlerden bahsetmişken , tablodaki alanı değilLatin1_General_BIN2 , dönüştürülen dize değişmezinin (veritabanı varsayılan harmanlamasının zımni bir harmanlaması ile ) nasıl olduğuna dikkat edin. Bu filtrenin büyük / küçük harfe duyarsız (eski harmanlama) veya büyük / küçük harfe duyarlı (yeni harmanlama) olup olmayacağına dair bir tahmininiz var mı? Görmek için aşağıdakileri çalıştırın:

    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';

    İadeler:

    Col1
    ----
    a
    A

    D'oh! Bu sorgu için yalnızca hafif bir (veya belki daha önemli?) Performans isabeti CONVERT_IMPLICIT()değil, aynı zamanda istenen büyük / küçük harfe duyarlı bir şekilde davranmaz.

    Ergo, harmanlama zaten tabloları olan bir DB'de değiştirilirse, evet, hem performans hem de işlevsellik etkilenir.

    Harmanlama yeni bir DB'de ayarlanıyorsa, Paul zaten ikili bir harmanlamanın hızlı olsa da, muhtemelen beklendiği veya arzu edeceği şekilde sıralanmayacağını açıklayarak bunu zaten ele aldı.


Her zaman koşul başına harmanlama belirtebileceğiniz de not edilmelidir. HARMANLA fıkra eklenebilir WHEREkoşullar, ORDER BYbir dize kabul eden herhangi bir yerde ve en.

Örnek 1 (NEREDE koşulu):

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;

İadeler:

SQL-CaseSensitive
-----------------
b
B

Windows-CaseSensitive
-----------------
A
b
B

Örnek 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;

İadeler:

Windows-CaseSensitive
-----------------
a
A
b
B

Windows-Binary
-----------------
A
B
a
b

Örnek 3 (IF ifadesi):

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];

İadeler:

DatabaseDefault-CaseInsensitive?
--------------------------------
1

{nothing}

Örnek 4 (işlev giriş parametresiyle ilişkilendir):

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/

İadeler:

UCS-2    UTF-16
------   -------
55356    127137

55.356 UCS-2 değeri, "vekil çiftteki" iki değerden ilki olması bakımından kısmen doğrudur. Ancak, _SCharmanlama açıkça verilmedikçe, UNICODE()işlev her karakteri yalnızca çift baytlık bir değer olarak görebilir ve çift çift baytlık bir vekil çiftinin nasıl düzgün şekilde işleneceğini bilmez.


GÜNCELLEME

Yukarıdaki tüm örneklerde bile, genellikle göz ardı edilen ve ikili karşılaştırmalar / harmanlamalarla reddedilen Büyük / Küçük Harfe Duyarlı karşılaştırmaların bir yönü, Unicode'un bir parçası olan normalleştirme (kompozisyon ve ayrışma).

Örnek 5 (ikili karşılaştırma büyük / küçük harfe duyarlı olmadığında ):

Büyük / küçük harfe duyarlı karşılaştırmalar, başka bir karakterle birlikte başka bir Unicode kod noktası olarak var olan başka bir karakteri oluşturan karakterlerin birleştirilmesine izin verir. Büyük / küçük harfe duyarlı karşılaştırmalar, karakteri oluşturmak için kullanılan kod noktalarını değil görüntülenebilir karakteri önemser.

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

İadeler:

Binary            ü     u + combining diaeresis
-------          ---   -------------------------
{nothing}

Case-Sensitive    ü     u + combining diaeresis
---------------  ---   -------------------------
Equal             ü     ü

Büyük / küçük harfe duyarlı karşılaştırmalar, geniş karakterlerin geniş olmayan eşdeğerlerine eşit olmasını da sağlar.

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];

İadeler:

Binary
---------------
Values are different


Case-Sensitive
---------------
Values are the same

Ergo:

İKİLİ ( _BINve _BIN2) harmanlamalar Büyük / Küçük Harfe Duyarlı değildir !

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.