不区分大小写的排序规则如何工作?

coc*_*lla 19 sql-server collation

SQL Server 中的默认排序规则类型允许针对不区分大小写的字符串进行索引,但数据的大小写仍然保留。这实际上是如何工作的?我正在寻找实际的具体细节、位和字节,或详细解释它的好资源。

create table casetest (fruitnames nvarchar(50) not null);
create unique index IX_fruitnames on casetest(fruitnames);

insert into casetest values ('apples');
insert into casetest values ('Pears');
-- this insert fails
insert into casetest values ('pears');

-- this yields 'Pears' as a result
select * from casetest (forceseek) where fruitnames = 'PEARS'

update casetest set fruitnames = 'pears' where fruitnames = 'pEArs'

-- this yields 'pears' as a result
select * from casetest (forceseek) where fruitnames = 'PEARS'
Run Code Online (Sandbox Code Playgroud)

罗伯特·谢尔顿 (Robert Sheldon)撰写的有关 SQL Server 排序规则的问题您太害羞了,介绍了如何使用排序规则。它不包括整理的工作原理。我对如何有效地创建/查询索引而不关心大小写感兴趣,同时存储案例数据。

Sol*_*zky 26

索引不区分大小写的字符串,但数据的大小写仍然存在。这实际上是如何工作的?

这实际上不是 SQL Server 特定的行为,它只是这些事情的一般工作方式。

所以,数据就是数据。如果您专门谈论索引,则需要按原样存储数据,否则每次都需要在主表中查找才能获取实际值,并且不可能有覆盖索引(在至少不适用于字符串类型)。

表/聚集索引或非聚集索引中的数据包含任何整理/排序信息。它只是数据。排序规则(区域设置/文化规则和敏感性)只是附加到列的元数据,并在调用排序操作时使用(除非被COLLATE子句),这将包括索引的创建/重建。由非二进制排序规则定义的规则用于生成排序键,它们是字符串的二进制表示(二进制排序规则中不需要排序键)。这些二进制表示包含所有区域设置/文化规则和选定的敏感性。排序键用于按正确的顺序放置记录,但它们本身并不存储在索引或表中。它们没有被存储(至少我没有在索引中看到这些值并且被告知它们没有被存储)因为:

  1. 排序并不是真正需要它们,因为它们只是与表或索引中的行的顺序相同。但是,索引的物理顺序只是排序,而不是比较。
  2. 虽然存储它们可能会使比较更快,但它也会使索引更大,因为单个字符的最小大小为 5 个字节,而这只是(排序键结构的)“开销”。大多数字符每个都是 2 个字节,如果有重音则加 1 个字节,如果是大写则加 1 个字节。例如,“e”是一个 7 字节的密钥,“E”和“é”都是 8 个字节,而“É”是一个 9 字节的密钥。因此,最后不值得存储这些。

有两种类型的排序规则:SQL Server 和 Windows。

数据库服务器

SQL Server 排序规则(名称以 开头的排序规则SQL_)是较旧的、SQL Server 2000 之前的排序/比较方式(尽管很遗憾,SQL_Latin1_General_CP1_CI_AS仍然是美国英语操作系统上的默认安装方式)。在这个较旧的、简单的、非 Unicode 模型中,语言环境、代码页和各种敏感度的每个组合都被赋予了该代码页中每个字符的静态映射。每个字符都分配了一个值(即排序权重)以表示它与其他字符的相等程度。此模型中的比较似乎进行了两次操作:

  1. 首先,它删除所有重音符号(例如“  ü  ”变成“  u  ”),将“ Æ  ”等字符扩展 为“  A  ”和“  E  ”,然后进行初始排序,使单词按自然顺序排列(您将如何希望在字典中找到它们)。
  2. 然后,它逐个字符地根据每个字符的这些潜在值来确定相等性。第二部分是 mustaccio 在他的回答中所描述的。

在这些排序规则中唯一可以调整的敏感度是:“case”和“accent”(“width”、“kana type”和“variation selector”不可用)。此外,这些排序规则都不支持补充字符(这是有道理的,因为它们是特定于 Unicode 的,并且这些排序规则仅适用于非 Unicode 数据)。

这种方法适用于对非UnicodeVARCHAR数据。区域设置、代码页、区分大小写和区分重音的每个唯一组合都有一个特定的“排序 ID”,您可以在以下示例中看到:

SELECT COLLATIONPROPERTY(N'SQL_Latin1_General_CP1_CI_AS', 'SortID'), -- 52
       COLLATIONPROPERTY(N'SQL_Latin1_General_CP1_CS_AS', 'SortID'), -- 51
       COLLATIONPROPERTY(N'Latin1_General_100_CI_AS',     'SortID'); --  0
Run Code Online (Sandbox Code Playgroud)

前两个排序规则之间的唯一区别是区分大小写。第三个排序规则是 Windows 排序规则,因此没有静态映射表。

此外,这些排序规则的排序和比较速度应该比 Windows 排序规则更快,因为它是字符排序权重的简单查找。然而,这些排序规则的功能也少得多,如果可能的话,通常应该避免。

视窗

Windows 排序规则(名称不以开头的排序规则SQL_)是较新的(从 SQL Server 2000 开始)排序/比较方式。在这个较新、复杂的 Unicode 模型中,语言环境、代码页和各种敏感性的每种组合都没有给出静态映射。一方面,此模型中没有代码页。此模型为每个字符分配一个默认排序值,然后每个区域设置/文化可以将排序值重新分配给任意数量的字符。这允许多种文化以不同的方式使用相同的字符。如果多种语言不使用相同的字符(并且如果其中之一不需要重新分配任何值并且可以简单地使用默认值),这确实允许使用相同的排序规则对多种语言进行自然排序。

此模型中的排序值不是单个值。它们是为基本字母、任何变音符号(即重音符号)、大小写等分配相对权重的值数组。如果排序规则区分大小写,则使用该数组的“大小写”部分,否则将被忽略(因此,不敏感)。如果排序规则对重音敏感,则使用数组的“变音符号”部分,否则将被忽略(因此不敏感)。

此模型中的比较是多遍操作:

  1. 首先,字符串被规范化,以便表示相同字符的各种方式将等同。例如,“ ü ”可以是单个字符/代码点 (U+00FC)。您还可以将非重音的“ u ”(U+0075)与组合分音符̈ ”(U+0308)结合起来得到:“ ü ”,它不仅在渲染时看起来相同(除非有问题您的字体),但也被认为与单字符版本 (U+00FC) 相同,除非使用二进制排序规则(比较字节而不是字符)。规范化将单个字符分解为多个部分,其中包括对“ Æ  ”等字符的扩展 (如上文针对 SQL Server 排序规则所述)。
  2. The comparison operation in this model goes character by character per each sensitivity. Sort keys for the strings are determined by applying the appropriate elements of each characters collation array of values based on which sensitivities are "sensitive". The sort key values are arranged by all of the primary sensitivities of each character (the base character), followed by all of the secondary sensitivities (diacritic weight), followed by the case weight of each character, and so on.
  3. Sorting is performed based on the calculated sort keys. With each sensitivity grouped together, you can get a different sort order than you would with an equivalent SQL Server collation when comparing strings of multiple characters, and accents are involved, and the collation is accent-sensitive (and even more so if the collation is also case-sensitive).

For more details on this sorting, I will eventually publish a post that shows the sort key values, how they are calculated, the differences between SQL Server and Windows collations, etc. But for now, please see my answer to: Accent Sensitive Sort (please note that the other answer to that question is a good explanation of the official Unicode algorithm, but SQL Server instead uses a custom, though similar, algorithm, and even a custom weight table).

可以在这些排序规则中调整所有敏感度:“case”、“accent”、“width”、“kana type”和“variation selector”(从 SQL Server 2017 开始,仅适用于日语排序规则)。此外,其中一些排序规则(与 Unicode 数据一起使用时)支持补充字符(从 SQL Server 2012 开始)。这种方法适用于NVARCHAR VARCHAR数据(甚至非 Unicode 数据)。VARCHAR通过首先在内部将值转换为 Unicode,然后应用排序/比较规则来应用于非 Unicode数据。


请注意:

  1. SQL Server 没有通用的默认排序规则。有一个安装默认值,它根据安装时操作系统的当前区域设置/语言设置而有所不同(不幸SQL_Latin1_General_CP1_CI_AS的是,对于美国英语系统,请为此建议投票)。这可以在安装过程中更改。然后,此实例级排序规则为[model]DB设置排序规则,DB 是创建新 DB 时使用的模板,但在执行时可以CREATE DATABASE通过指定COLLATE子句更改排序规则。此数据库级排序规则用于变量和字符串文字,以及COLLATE未指定子句时新(和更改!)列的默认值(问题中的示例代码就是这种情况)。
  2. 有关排序规则/编码/Unicode 的更多信息,请访问:排序规则信息


mus*_*cio 5

通常这是使用归类表来实现的,归类表为每个字符分配一定的分数。排序例程有一个比较器,它使用一个适当的表,无论是默认的还是明确指定的,使用它们的排序分数逐个字符地比较字符串。例如,如果特定的整理表为“a”分配 1 分,为“A”分配 201 分,并且此特定实现中较低的分值意味着更高的优先级,则“a”将在“A”之前进行排序。另一个表可能会分配反向分数:201 分配给“a”,1 分配给“A”,并且排序顺序将随后颠倒。另一个表可能会为“a”、“A”、“Á”和“Å”分配相等的分数,这将导致不区分大小写和重音的比较和排序。

类似地,当将索引键与谓词中提供的值进行比较时,会使用这种基于整理表的比较器。