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.
İkili harmanlamalar, büyük / küçük harfe duyarlı değildir; her şey hassastır! Dolayısıyla, ikili bir harmanlama kullanarak ( _BIN
veya 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ı?
Harmanlamalar sadece karşılaştırmaları değil sıralamayı da etkiler. İkili harmanlama , her baytınASCII
veya UNICODE
bayt değerine ( sırasıyla VARCHAR
veya NVARCHAR
sı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ı?
Uygulamanız için belirli geriye dönük uyumluluk gereksinimleriniz olmadığı sürece , elbette, ilk etapta ikili bir harmanlama istediğinizi varsayarak, harmanlama BIN2
yerine kullanmalısınız BIN
. BIN2
Alfabe, 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, _BIN2
harmanlamaların, bu Ordinal
seç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. _BIN2
alfabe, tabii ki).
_BIN2
Harmanlamalarla 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" ;-)).
Unicode verileri (yani N
, veri türünün NChar
veya 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 NCHAR
veya NVARCHAR
dize 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.
Ç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 COLLATE
fı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 WHERE
koşullar, ORDER BY
bir 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, _SC
harmanlama 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İ ( _BIN
ve _BIN2
) harmanlamalar Büyük / Küçük Harfe Duyarlı değildir !