排序规则限制和行为区别 - Amazon Aurora
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

排序规则限制和行为区别

Babelfish 使用 ICU 库进行排序规则支持。PostgreSQL 使用特定版本的 ICU 构建,最多可以匹配一个排序规则版本。不同版本之间的差异是不可避免的,随着语言的变化,随着时间的推移,会产生一些细微的变化。在下面的列表中,您可以找到 Babelfish 排序规则的一些已知限制和行为变体:

  • 索引和排序规则类型依赖关系 – 当库版本更改时,依赖于 International Components for Unicode (ICU) 排序规则库(Babelfish 使用的库)的用户定义类型的索引不会失效。

  • COLLATIONPROPERTY 函数 – 排序规则属性仅针对支持的 Babelfish BBF 排序规则实现。有关更多信息,请参阅 Babelfish supported collations table

  • Unicode 排序规则差异 – SQL Server 的 SQL 排序规则对 Unicode 编码的数据(ncharnvarchar)的排序方式不同于非 Unicode 编码的数据(charvarchar)。Babelfish 数据库始终是 UTF-8 编码的,并且始终一致地应用 Unicode 排序规则,而无论数据类型如何,因此针对 charvarchar 的排序顺序与针对 ncharnvarchar 的排序顺序相同。

  • 二级相等排序规则和排序行为 – 原定设置的 ICU Unicode 二级相等 (CI_AS) 排序规则将标点符号和其他非字母数字字符排序在数字字符之前,将数字字符排序在字母字符之前。但是,标点符号和其他特殊字符的顺序不同。

  • 三级排序规则,ORDER BY 的解决方法SQL_Latin1_General_Pref_CP1_CI_AS 之类的 SQL 排序规则支持 TERTIARY_WEIGHTS 函数并能够对 CI_AS 排序规则中进行同等比较的字符串进行排序,大写字母优先排序:ABCABcAbCAbcaBCaBcabC,最后是 abc。因此,DENSE_RANK OVER (ORDER BY column) 分析函数将这些字符串评估为具有相同的排名,但首先在分区中对它们用大写字母进行排序。

    您可以通过添加一个 COLLATE 子句到指定 @colCaseFirst=upper 的三级 CS_AS 排序规则的 ORDER BY 子句中来获取与 Babelfish 相似的结果。但是,colCaseFirst 修饰符仅适用于三级相等的字符串(而不是 CI_AS 排序规则之类的二级相等字符串)。因此,您无法使用单个 ICU 排序规则模拟三级 SQL 排序规则。

    作为解决办法,我们建议您修改使用 SQL_Latin1_General_Pref_CP1_CI_AS 排序规则的应用程序,以首先使用 BBF_SQL_Latin1_General_CP1_CI_AS 排序规则。然后将 COLLATE BBF_SQL_Latin1_General_Pref_CP1_CS_AS 添加到此列的任何 ORDER BY 子句中。

  • 字符扩展 – 字符扩展将单个字符视为等于主级别的一系列字符。SQL Server 的原定设置 CI_AS 排序规则支持字符扩展。ICU 排序规则仅支持对不区分重音的排序规则进行字符扩展。

    当需要扩展字符时,请使用 AI 排序规则进行比较。但是,LIKE 运算符目前不支持此类排序规则。

  • char 和 varchar 编码 – 当将 SQL 排序规则用于 charvarchar 数据类型时,ASCII 127 之前的字符的排序顺序由该 SQL 排序规则的特定代码页决定。对于 SQL 排序规则,声明为 charvarchar 的字符串可能与声明为 ncharnvarchar 的字符串的排序方式不同。

    PostgreSQL 使用数据库编码对所有字符串进行编码,因此,所有字符转换为 UTF-8 并使用 Unicode 规则进行排序。

    由于 SQL 排序规则使用 Unicode 规则对 nchar 和 nvarchar 数据类型进行排序,因此,Babelfish 会使用 UTF-8 对服务器上的所有字符串进行编码。Babelfish 使用 Unicode 规则对 nchar 和 nvarchar 字符串进行排序的方式与对 char 和 varchar 字符串进行排序的方式相同。

  • 补充字符 – SQL Server 函数 NCHARUNICODELEN 支持 Unicode 基本多语言平面 (BMP) 之外的代码点的字符。相比之下,非 SC 排序规则使用代理对字符来处理补充字符。对于 Unicode 数据类型,SQL Server 可以使用 UCS-2 最多表示 65535 个字符,如果使用补充字符,则表示完整的 Unicode 范围(1114114 个字符)。

  • 区分假名 (KS) 排序规则 – 区分假名 (KS) 排序规则是以不同方式处理 HiraganaKatakana 日语假名字符的排序规则。ICU 支持日语排序规则标准 JIS X 4061。现在已弃用的 colhiraganaQ [on | off] 区域设置修饰符可能会提供与 KS 排序规则相同的功能。但是,Babelfish 目前不支持与 SQL Server 同名的 KS 排序规则。

  • 区分全角和半角 (WS) 排序规则 – 如果单字节字符(半角)和表示为双字节字符(全角)的同一个字符被区别对待,则排序规则被称为区分全角和半角 (WS)。Babelfish 目前不支持与 SQL Server 同名的 WS 排序规则。

  • 变体选择器敏感性 (VSS) 排序规则 – 变体选择器敏感性 (VSS) 排序规则区分日语排序规则 Japanese_Bushu_Kakusu_140Japanese_XJIS_140 中的表意文字变体选择器。变体序列由基本字符加上一个额外的变体选择器组成。如果您不选择 _VSS 选项,则在比较中不考虑变体选择器。

    Babelfish 目前不支持 VSS 排序规则。

  • BIN 和 BIN2 排序规则 – BIN2 排序规则根据代码点顺序对字符进行排序。UTF-8 的逐字节二进制顺序保留了 Unicode 代码点顺序,因此这也可能是性能最佳的排序规则。如果 Unicode 代码点顺序适用于应用程序,请考虑使用 BIN2 排序规则。但是,使用 BIN2 排序规则可能会导致数据以一种文化上意想不到的顺序在客户端上显示。随着时间的推移,小写字符的新映射将添加到 Unicode 中,因此 LOWER 函数在不同版本的 ICU 上可能会有所不同。这是比较一般的排序规则版本控制问题的特殊情况,而不是 BIN2 排序规定的特定情况。

    Babelfish 以 Babelfish 发行版提供 BBF_Latin1_General_BIN2 排序规则,以便按 Unicode 代码点顺序进行排序。在 BIN 排序规则中,只有第一个字符被排序为 wchar。剩余字符按字节排序,以有效地根据其编码按代码点顺序排序。这种方法不遵循 Unicode 排序规则,也不受 Babelfish 支持。

  • 非确定性排序规则和 CHARINDEX 限制 – 对于早于版本 2.1.0 的 Babelfish 版本,您不能将 CHARINDEX 与非确定性排序规则结合使用。原定设置情况下,Babelfish 使用不区分大小写(不确定性)排序规则。对较旧版本的 Babelfish 使用 CHARINDEX 会引发以下运行时错误:

    nondeterministic collations are not supported for substring searches
    注意

    此限制和解决方法仅适用于 Babelfish 版本 1.x(Aurora PostgreSQL 13.x 版本)。Babelfish 2.1.0 及更高版本没有此问题。

    您可以通过以下方式之一解决此问题:

    • 将表达式显式转换为区分大小写的排序规则,然后通过应用 LOWER 或 UPER 将两个参数转换为大写。例如,SELECT charindex('x', a) FROM t1 将变为以下内容:

      SELECT charindex(LOWER('x'), LOWER(a COLLATE sql_latin1_general_cp1_cs_as)) FROM t1
    • 创建一个 SQL 函数 f_charindex,然后将 CHARINDEX 调用替换为对以下函数的调用:

      CREATE function f_charindex(@s1 varchar(max), @s2 varchar(max)) RETURNS int AS BEGIN declare @i int = 1 WHILE len(@s2) >= len(@s1) BEGIN if LOWER(@s1) = LOWER(substring(@s2,1,len(@s1))) return @i set @i += 1 set @s2 = substring(@s2,2,999999999) END return 0 END go