rookie099 Asked: 2019-06-20 06:22:07 +0800 CST2019-06-20 06:22:07 +0800 CST 2019-06-20 06:22:07 +0800 CST PostgreSQL:排序规则“C”和“C.UTF-8”之间的区别 772 C在 PostgreSQL 中,排序规则和排序规则有什么区别C.UTF-8? 两者都出现在pg_collation. 不管数据库的实际编码是什么,是否可能与编码C.UTF-8相同?CUTF-8 postgresql collation 3 个回答 Voted Best Answer Solomon Rutzky 2019-06-20T09:24:11+08:002019-06-20T09:24:11+08:00 PostgreSQL 文档还有很多不足之处(只是说'?)。 首先,特定数据库只有一种编码,因此C在C.UTF-8您的 UTF-8 数据库中都使用 UTF-8 编码。 对于libc排序规则:按照惯例,通常排序规则名称是以下结构的真正的两部分名称: {locale_name}.{encoding_name} “语言环境”(即“文化”)是一组特定于语言的排序规则(LC_COLLATE)和大小写规则(LC_CTYPE)。尽管有时会有重叠,但这实际上与这些数据的存储方式没有任何关系。 “编码”是数据的存储方式(即什么字节序列等同于哪个字符)。即使有时存在重叠,但这实际上与使用编码的任何特定语言的排序和大写规则没有任何关系(某些编码可以被多种语言使用,这些语言在其中一种或两种中可能具有完全不同的规则那些领域)。 为了说明,考虑存储韩国数据: ko_KR是语言环境。 可用于此语言环境的可能编码有: EUC_KR(扩展 UNIX 代码-KR) JOHAB UHC(统一韩文代码/Windows949) UTF8(Unicode 的 8 位编码) 还要考虑以下内容,取自“排序规则支持:libc 排序规则”文档(强调添加): 例如,操作系统可能会提供一个名为de_DE.utf8. 然后将创建一个以编码initdb命名的排序规则......它还将创建一个带有从名称中剥离的标签的排序规则。所以你也可以在 name 下使用排序规则,这样写起来不那么麻烦,并且使 name 不那么依赖于编码...... de_DE.utf8UTF8.utf8de_DE ... 在任何特定数据库中,只有使用该数据库编码的排序规则才有意义。中的其他条目pg_collation将被忽略。因此,剥离的排序规则名称,例如,de_DE可以被认为在给定数据库中是唯一的,即使它不是全局唯一的。建议使用剥离的排序规则名称,因为如果您决定更改为另一种数据库编码,它将减少您需要更改的事情。但是请注意,default无论数据库编码如何,都可以使用C、 和排序规则。POSIX 意思是,在使用 UTF-8 编码的数据库中,en_US是en_US.UTF8等价的。但是,在该数据库和使用LATIN1编码的数据库之间,en_US排序规则是不等价的。 那么,这是否意味着C和C.UTF-8相同? 不,那太容易了!!!C排序规则是上述行为的一个例外。排序规则是一组简单的C规则,无论数据库的编码如何,行为都应该是一致的(这可以通过仅将美国英语字母表“az”和“AZ”识别为“字母”来实现) ,并按字节值排序,这对于您可用的编码应该是相同的)。 C.UTF-8与基本规则相比,排序规则实际上是一组稍微增强的规则C。实际上可以看到这种差异,pg_collation因为collcollate和collctype列的值在 和 的行之间是不同C的C.UTF-8。 我整理了一组测试查询来说明这两个排序规则之间的一些异同,以及与en_GB(和隐含的en_GB.utf8)比较。我从Daniel Vérité 的回答中提供的查询开始,对它们进行了增强,希望能更清楚地了解显示和未显示的内容,并添加了一些查询。结果告诉我们: C并且C.UTF-8实际上是不同的规则集,即使只是略有不同,基于它们在(最终查询)中的collcollate和collctype列中的各自值pg_collation C.UTF-8扩展被认为是“字母”的字符 C.UTF-8,不像C(但像en_GB),识别无效的Unicode代码点(即U + 0378)并将它们排序到顶部 C.UTF-8,类似C(但不同en_GB),按代码点对非美国英语字母字符进行排序 ucs_basic似乎等同于C(在文档中说明) 您可以在以下位置找到并执行查询:db<>fiddle Daniel Vérité 2019-06-21T03:20:00+08:002019-06-21T03:20:00+08:00 是否可能 C.UTF-8 与编码 UTF-8 的 C 相同 不。例如,在 Debian 10 Linux 上考虑 UTF-8 数据库中的这些差异: postgres=# select upper('é' collate "C"), upper('é' collate "C.UTF-8"); upper | upper -------+------- é | É (1 row) postgres=# select ('A' < E'\u0378' collate "C"), ('A' < E'\u0378' collate "C.UTF-8"); ?column? | ?column? ----------+---------- t | f (1 row) (U+0378 不对应 Unicode 中的任何有效字符)。 另一个具有有效 Unicode 字符的示例(左侧是'THUMBS UP SIGN' U+1F44D): => select '?' < 'A' collate "C"; ?column? ---------- f (1 row) => select '?' < 'A' collate "C.UTF-8"; ?column? ---------- t (1 row) 当lc_collate是“C”(或“POSIX”)时,比较由 PostgreSQL 内部完成。在这种情况下,它使用 比较字符串的字节表示memcmp。 在 libc 是提供者(collprovider='c'in pg_collation)的其他情况下,比较是由strcoll_lC 库完成的,因此 PostgreSQL 本身不对结果负责,如上面的反例所示,没有理由相信它将是相同的。 至少对于 libc 支持的排序规则是这样。从 Postgres 版本 10 开始,可以使用 ICU 排序规则。这些排序规则在操作系统之间是一致的。 血淋淋的细节可以在backend/utils/adtvarlena.c的源代码中找到,尤其是varstrmp_cmp函数。 Michael Hooreman 2019-06-20T06:48:36+08:002019-06-20T06:48:36+08:00 从 postgresql 文档中,https ://www.postgresql.org/docs/11/collation.html : 23.2.2.1。标准归类 在所有平台上,名为 default、C 和 POSIX 的排序规则都可用。根据操作系统支持,可能会提供其他排序规则。默认排序规则选择在数据库创建时指定的 LC_COLLATE 和 LC_CTYPE 值。C 和 POSIX 排序规则都指定了“传统 C”行为,其中只有 ASCII 字母“A”到“Z”被视为字母,并且严格按字符代码字节值进行排序。 此外,SQL 标准排序规则名称 ucs_basic 可用于编码 UTF8。它等效于 C 并按 Unicode 代码点排序。 所以,如果我的理解是正确的,C 是 ASCII,而不是 UTF8。
PostgreSQL 文档还有很多不足之处(只是说'?)。
首先,特定数据库只有一种编码,因此
C
在C.UTF-8
您的 UTF-8 数据库中都使用 UTF-8 编码。对于libc排序规则:按照惯例,通常排序规则名称是以下结构的真正的两部分名称:
{locale_name}.{encoding_name}
“语言环境”(即“文化”)是一组特定于语言的排序规则(
LC_COLLATE
)和大小写规则(LC_CTYPE
)。尽管有时会有重叠,但这实际上与这些数据的存储方式没有任何关系。“编码”是数据的存储方式(即什么字节序列等同于哪个字符)。即使有时存在重叠,但这实际上与使用编码的任何特定语言的排序和大写规则没有任何关系(某些编码可以被多种语言使用,这些语言在其中一种或两种中可能具有完全不同的规则那些领域)。
为了说明,考虑存储韩国数据:
ko_KR
是语言环境。EUC_KR
(扩展 UNIX 代码-KR)JOHAB
UHC
(统一韩文代码/Windows949)UTF8
(Unicode 的 8 位编码)还要考虑以下内容,取自“排序规则支持:libc 排序规则”文档(强调添加):
意思是,在使用 UTF-8 编码的数据库中,
en_US
是en_US.UTF8
等价的。但是,在该数据库和使用LATIN1
编码的数据库之间,en_US
排序规则是不等价的。那么,这是否意味着
C
和C.UTF-8
相同?不,那太容易了!!!
C
排序规则是上述行为的一个例外。排序规则是一组简单的C
规则,无论数据库的编码如何,行为都应该是一致的(这可以通过仅将美国英语字母表“az”和“AZ”识别为“字母”来实现) ,并按字节值排序,这对于您可用的编码应该是相同的)。C.UTF-8
与基本规则相比,排序规则实际上是一组稍微增强的规则C
。实际上可以看到这种差异,pg_collation
因为collcollate
和collctype
列的值在 和 的行之间是不同C
的C.UTF-8
。我整理了一组测试查询来说明这两个排序规则之间的一些异同,以及与
en_GB
(和隐含的en_GB.utf8
)比较。我从Daniel Vérité 的回答中提供的查询开始,对它们进行了增强,希望能更清楚地了解显示和未显示的内容,并添加了一些查询。结果告诉我们:C
并且C.UTF-8
实际上是不同的规则集,即使只是略有不同,基于它们在(最终查询)中的collcollate
和collctype
列中的各自值pg_collation
C.UTF-8
扩展被认为是“字母”的字符C.UTF-8
,不像C
(但像en_GB
),识别无效的Unicode代码点(即U + 0378)并将它们排序到顶部C.UTF-8
,类似C
(但不同en_GB
),按代码点对非美国英语字母字符进行排序ucs_basic
似乎等同于C
(在文档中说明)您可以在以下位置找到并执行查询:db<>fiddle
不。例如,在 Debian 10 Linux 上考虑 UTF-8 数据库中的这些差异:
(U+0378 不对应 Unicode 中的任何有效字符)。
另一个具有有效 Unicode 字符的示例(左侧是'THUMBS UP SIGN' U+1F44D):
当
lc_collate
是“C”(或“POSIX”)时,比较由 PostgreSQL 内部完成。在这种情况下,它使用 比较字符串的字节表示memcmp
。在 libc 是提供者(
collprovider='c'
inpg_collation
)的其他情况下,比较是由strcoll_l
C 库完成的,因此 PostgreSQL 本身不对结果负责,如上面的反例所示,没有理由相信它将是相同的。至少对于 libc 支持的排序规则是这样。从 Postgres 版本 10 开始,可以使用 ICU 排序规则。这些排序规则在操作系统之间是一致的。
血淋淋的细节可以在backend/utils/adtvarlena.c的源代码中找到,尤其是
varstrmp_cmp
函数。从 postgresql 文档中,https ://www.postgresql.org/docs/11/collation.html :
所以,如果我的理解是正确的,C 是 ASCII,而不是 UTF8。