2017-03-18 34 views
10

由於SQL服務器的排序規則不能區分ssß,我想要更改特定的排序規則在的建議表中的列表SQL_Latin1_General_CP437_BIN2選擇一個二進制排序規則,可以區分Sql Server中nvarchar列的'ss'和'ß'

但是,我不確定這是否通常是一種好的做法。另外,我不知道比下面其他的含義:

  • 更改排序順序:由於我從來沒有排序此列中的數據,它可能不是爲我一個問題。但是,如果您認爲不然,請告訴我。
  • 更改不區分大小寫區分大小寫:由於我的應用程序始終以小寫字母提供文本,所以我認爲這種更改對我來說也不會有問題。但是,如果您認爲不然,請告訴我。

我很好奇這種改變的其他主要含義,如果有的話。

另外,我也想知道以下情況之一將是最適合這樣的場景:

SQL_Latin1_General_CP437_BIN

說明: Latin1的祕書長,二進制排序爲Unicode數據,對於非Unicode數據,代碼頁437上的SQL Server排序順序30


SQL_Latin1_General_CP437_BIN2

說明: Latin1的祕書長,二進制代碼點比較排序爲Unicode數據,SQL Server的排序代碼頁437訂購30非Unicode數據


SQL_Latin1_General_CP850_BIN

描述: Latin1-General,Unicode數據的二進制排序,SQL Server排序順序4 0上的代碼頁850的非Unicode數據


SQL_Latin1_General_CP850_BIN2

說明: Latin1的祕書長,二進制代碼點比較排序爲Unicode數據,SQL Server的排序代碼頁850訂單40對於非Unicode數據

如果您認爲還有其他排序規則更適合此場景,請同時提及這些排序規則。


19.03更新。2017年: 要有人來對這個問題:

  • 必須檢查均來自@srutzky和@SqlZim的答案,以及相關引用的資源。在這種情況下,你不想衝進去。
  • 由於改變排序規則並不適合膽小的人:P,保留表數據的備份可能會派上用場。
  • 還檢查列的依賴關係,如索引和約束;您可能需要刪除並創建這些內容,就像我的情況一樣。

玩得開心:)

+0

值得一看:https://support.microsoft.com/en-us/help/322112/comparing-sql-collat​​ions-to-windows-collat​​ions –

+2

我希望你不介意,但我編輯您的問題標題以包含'ss'和'ß'這一特定問題,以便其他人可以在將來更容易地找到此問題。 – SqlZim

+0

@SqlZim一點都沒有。謝謝你 –

回答

9

有關排序規則的幾件事情:

  1. SQL_排序規則被棄用的SQL Server 2000(是的,2000年)。如果你可以避免使用它們,你應該(但是這並不意味着如果沒有迫切的需要就去改變一堆東西!)。

    SQL_排序問題實際上僅與VARCHAR(即非Unicode)數據有關,因爲NVARCHAR(即Unicode)數據使用來自OS的規則。但不幸的是,排序和比較VARCHAR數據的規則使用了簡單的映射,並沒有包含更復雜的語言規則。這就是爲什麼ssß使用相同的SQL_Latin1_General_CP1_CI_AS歸類存儲爲VARCHAR時不等同。在詞語中間使用時,這些不贊成使用的排序規則也無法給出較低的重量。排序規則(即Windows排序規則)對VARCHARNVARCHAR均使用相同的規則,所以VARCHAR處理更穩健,更符合NVARCHAR

  2. _BIN排序規則從SQL Server 2005開始不推薦使用。如果您可以避免使用它們,那麼您應該(但並不意味着在沒有迫切需要的情況下更改一大堆東西!)。

    排序問題與_BIN排序相當微妙,因爲它隻影響排序。 _BIN_BIN2之間的比較是相同的,因爲它們在字節級進行比較(因此沒有語言規則)。但是,由於SQL Server(和Windows/PC)是Little Endian,所以實體以反向字節順序存儲。這在處理雙字節「字符」時變得很明顯,這是什麼NVARCHAR數據是:UTF-16 Little Endian。這意味着Unicode碼位U + 1216在Big Endian系統上具有0x1216的十六進制/二進制表示,但在Little Endian系統上存儲爲0x1612。爲了讓最後一點的重要性(希望)變得顯而易見:_BIN排序規則將逐字節地比較(在第一個字符之後),並因此將U + 1216看作是0x16然後是0x12,而_BIN2排序規則將按代碼點比較代碼點,因此將U + 1216看作是0x12,然後是0x16。

  3. 這種特殊的列NVARCHAR,因此單單只是這列(使用SQL_Latin1_General_CP1_CI_AS不會等同ssß一個VARCHAR欄),那裏是由於爲Unicode SQL_Latin1_General_CP437_BIN2SQL_Latin1_General_CP850_BIN2之間沒有差別是一個單一的,包容性組。

  4. 對於VARCHAR數據,就不會有差別,因爲它們是不同的代碼頁(437850),並且這兩個都是比你現在用一個(CP1 ==代碼頁1252)不同。

  5. 雖然使用二進制排序常常是矯枉過正,在這種情況下,可能有必要考慮到只有一個語言環境/文化不等於ßss:匈牙利語。使用匈牙利語整理可能會有一些你不想要的語言規則(或至少不會期望),所以二進制整理似乎是更好的選擇(只是不是你詢問的4個問題中的任何一個):-) 。請記住,通過使用二進制排序規則,您不僅可以放棄所有語言規則,還會失去將相同字符的不同版本(例如ALatin Capital Letter A U+0041)和Fullwidth Latin Capital Letter A U+FF21))等同的能力。

    使用以下查詢,看看有什麼排序規則都是非二進制和不等同這些字符:

    DECLARE @SQL NVARCHAR(MAX) = N'DECLARE @Counter INT = 1;'; 
    
    SELECT @SQL += REPLACE(N' 
        IF(N''ß'' COLLATE {Name} = N''ss'' COLLATE {Name}) 
        BEGIN 
        RAISERROR(N''%4d. {Name}'', 10, 1, @Counter) WITH NOWAIT; 
        SET @Counter += 1; 
        END; 
    ', N'{Name}', col.[name]) + NCHAR(13) + NCHAR(10) 
    FROM sys.fn_helpcollations() col 
    WHERE col.[name] NOT LIKE N'SQL[_]%' 
    AND col.[name] NOT LIKE N'%[_]BIN%' 
    ORDER BY col.[name] 
    
    --PRINT @SQL; 
    EXEC (@SQL); 
    

所以:

  • 如果你要使用二進制排序,使用類似Latin1_General_100_BIN2
  • 你這樣做不是需要更改整個數據庫及其所有表的整理。這是很多的工作,唯一的「內置」機制做到這一點是沒有記錄(即不支持)。
  • 如果您要更改數據庫的默認歸類,這會影響數據庫範圍項目(如表,列,索引,函數,存儲過程等)的名稱解析。含義:您需要將100%的應用程序觸及數據庫,以及觸及此數據庫的所有SQL Server代理作業等。
  • 如果大多數/所有使用此列的查詢都需要ßss被視爲不同,請繼續並更改列以使用Latin1_General_100_BIN2。這可能會需要丟棄以下依賴對象,然後ALTER TABLE後重建:

    • 指標
    • 唯一約束
    • 外鍵約束

    提示:一定要檢查當前列的NULL/NOT NULL設置,並在ALTER TABLE ... ALTER COLUMN ...語句中指定它,以使其不被更改。

  • 如果只有一些查詢需要這種不同的行爲,則可以基於每個條件(例如WHERE tab.[ThisColumn] LIKE N'%ss%' COLLATE Latin1_General_100_BIN2)僅覆蓋那些與COLLATE子句進行的比較操作。 COLLATE關鍵字只應在(操作員的)一方需要,因爲整理優先級會將其應用於另一方。
+1

謝謝你的詳細解答:) –

+1

非常徹底,並再次感謝您的迴應請求! – SqlZim

+0

@SqlZim我在這個問題上看到了賞金,並想說謝謝。這是非常友善和不必要的:-)。因爲我現在對接管有點內疚,現在得到更多分數,我繼續前進,並通過添加更多信息,主要是在第1點和第2點,讓它更值得加分。再加上一些方便的鏈接和關於最後一個項目。 :-) –

5

一般來說,BIN2將是可取的超過BIN,你可能要選擇在SQL排序規則Windows排序。例如Latin1_General_100_BIN2

Guidelines for Using BIN and BIN2 Collations

使用原則爲BIN排序規則

如果您的SQL Server應用程序與舊版本使用二進制排序規則的SQL Server進行交互,繼續使用二進制文件。二進制排序規則可能是混合環境更合適的選擇。


出於類似的原因是什麼剛被關於BIN2排序規則的規定,除非你有特殊要求,以保持向後兼容性問題,您應該傾斜向使用Windows排序規則而不是SQL服務器特定的排序規則(即以SQL開頭的排序現在被認爲有點「糟糕」;-))。
- @srutzky - Latin1_General_BIN performance impact when changing the database default collation


rextester演示:http://rextester.com/KIIDYH74471

create table t (
    a varchar(16) --collate SQL_Latin1_General_CP1_CI_AS /* default */ 
    , b varchar(16) --collate SQL_Latin1_General_CP1_CI_AS 
    , c nvarchar(16) --collate SQL_Latin1_General_CP1_CI_AS 
    , d nvarchar(16) --collate SQL_Latin1_General_CP1_CI_AS 
); 
insert into t values ('ss','ß',N'ss',N'ß'); 
select * 
    , case when a = b then '=' else '!=' end as [a=b] /* != */ 
    , case when a = d then '=' else '!=' end as [a=d] /* = */ 
    , case when c = b then '=' else '!=' end as [c=b] /* = */ 
    , case when c = d then '=' else '!=' end as [c=d] /* = */ 
from t; 

回報:

+----+---+----+---+-----+-----+-----+-----+ 
| a | b | c | d | a=b | a=d | c=b | c=d | 
+----+---+----+---+-----+-----+-----+-----+ 
| ss | ß | ss | ß | != | = | = | = | 
+----+---+----+---+-----+-----+-----+-----+ 

create table t (
    a varchar(16) collate Latin1_General_100_BIN2 
    , b varchar(16) collate Latin1_General_100_BIN2 
    , c nvarchar(16) collate Latin1_General_100_BIN2 
    , d nvarchar(16) collate Latin1_General_100_BIN2 
); 
insert into t values ('ss','ß',N'ss',N'ß'); 
select * 
    , case when a = b then '=' else '!=' end as [a=b] /* != */ 
    , case when a = d then '=' else '!=' end as [a=d] /* != */ 
    , case when c = b then '=' else '!=' end as [c=b] /* != */ 
    , case when c = d then '=' else '!=' end as [c=d] /* != */ 
from t; 

回報:

+----+---+----+---+-----+-----+-----+-----+ 
| a | b | c | d | a=b | a=d | c=b | c=d | 
+----+---+----+---+-----+-----+-----+-----+ 
| ss | ß | ss | ß | != | != | != | != | 
+----+---+----+---+-----+-----+-----+-----+ 
+0

感謝您的回答並分享其他資源。通過[其他問題](http://dba.stackexchange.com/questions/110911/latin1-general-bin-performance-impact-when-changing-the-database-default-collat​​i)的答案後,它似乎更改數據庫的排序規則(也是現有表格的文本列的排序規則)會產生更一致的結果和更好的性能。這是通常如何完成的? –

+1

@SayanPal我不得不說這取決於,但我會看看如果我能得到srutzky提供一些建議。 – SqlZim

+0

很好的研究:) +1 –