提问人:KahWee Teng 提问时间:4/20/2009 最后编辑:simhumilecoKahWee Teng 更新时间:12/25/2022 访问量:607781
utf8_general_ci 和 utf8_unicode_ci 有什么区别?
What's the difference between utf8_general_ci and utf8_unicode_ci?
答:
请参阅 mysql 手册,Unicode 字符集部分:
对于任何 Unicode 字符集, 使用 _general_ci排序规则比_unicode_ci排序规则的排序规则更快。 例如,比较 utf8_general_ci整理速度更快, 但稍微不那么正确,比 utf8_unicode_ci的比较。这 原因是 utf8_unicode_ci支持以下映射 作为扩展;也就是说,当一个 字符比较等于 其他字符的组合。为 例如,在德语和其他一些方面 语言“ß”等于“ss”。 utf8_unicode_ci还支持 收缩和可忽略的字符。 utf8_general_ci 是旧版排序规则 不支持扩展, 收缩或可忽略的字符。 它只能进行一对一 字符之间的比较。
因此,总而言之,utf_general_ci使用的比较集比应该实现整个标准的utf_unicode_ci更小、更不正确(根据标准)。general_ci集会更快,因为要执行的计算更少。
评论
utf8_unicode_ci
0
1
1/3
对于那些在 2020 年或以后仍然遇到这个问题的人来说,有更新的选择可能比这两个更好。例如,utf8_unicode_520_ci
。
所有这些排序规则都用于 UTF-8 字符编码。区别在于文本的排序和比较方式。
_unicode_ci
并且是两套不同的规则,用于根据我们期望的方式对文本进行排序和比较。较新版本的MySQL也引入了新的规则集,例如基于Unicode 5.2的等效规则,或者MySQL 8.x特定于基于Unicode 9.0的等效规则(并且没有等效变体)。现在阅读本文的人可能应该使用这些较新的排序规则之一,而不是 或 .下面对这些较旧排序规则的描述仅供参考。_general_ci
_unicode_520_ci
_0900_ai_ci
_general_ci
_unicode_ci
_general_ci
MySQL目前正在从旧的、有缺陷的UTF-8实现过渡。现在,您需要使用 utf8mb4
而不是 utf8
作为字符编码部分,以确保您获得固定版本。有缺陷的版本仍然用于向后兼容性,尽管它已被弃用。
主要区别
utf8mb4_unicode_ci
基于通用排序和比较的官方 Unicode 规则,该规则可在多种语言中准确排序。utf8mb4_general_ci
是一组简化的排序规则,旨在尽可能地做到最好,同时采取许多旨在提高速度的捷径。它不遵循 Unicode 规则,在某些情况下(例如使用特定语言或字符时)会导致不需要的排序或比较。在现代服务器上,这种性能提升几乎可以忽略不计。它是在服务器的CPU性能仅为当今计算机的一小部分的时代设计的。
utf8mb4_unicode_ci
优于utf8mb4_general_ci
的好处
utf8mb4_unicode_ci
,它使用 Unicode 规则进行排序和比较,它采用相当复杂的算法在各种语言和使用各种特殊字符时进行正确排序。这些规则需要考虑到特定语言的惯例;不是每个人都按照我们所说的“字母顺序”对他们的角色进行排序。
就拉丁语(即“欧洲”)语言而言,Unicode排序和MySQL中的简化排序没有太大区别,但仍存在一些差异:utf8mb4_general_ci
例如,Unicode 排序规则将“ß”排序为“ss”,将“Œ”排序为“OE”,而使用这些字符的人通常希望将它们排序为单个字符(可能分别像“s”和“e”)。
utf8mb4_general_ci
某些 Unicode 字符被定义为可忽略的,这意味着它们不应计入排序顺序,而应继续比较下一个字符。 正确处理这些问题。
utf8mb4_unicode_ci
在非拉丁语言中,例如亚洲语言或具有不同字母的语言,Unicode 排序和简化排序之间可能存在更多差异。遗嘱的适用性很大程度上取决于所使用的语言。对于某些语言来说,这将是相当不够的。utf8mb4_general_ci
utf8mb4_general_ci
你应该使用什么?
几乎可以肯定的是,没有理由再使用,因为我们已经忽略了CPU速度足够低的点,因此性能差异很重要。几乎可以肯定的是,您的数据库将受到其他瓶颈的限制。utf8mb4_general_ci
过去,有些人建议使用,除非准确排序足够重要,足以证明性能成本是合理的。如今,这种性能成本几乎消失了,开发人员正在更加认真地对待国际化。utf8mb4_general_ci
有一种观点认为,如果速度对你来说比准确性更重要,那么你还不如根本不做任何排序。如果您不需要算法的准确性,那么使算法更快是微不足道的。因此,出于速度原因,可能不需要这种折衷方案,也可能不适合出于准确性原因。utf8mb4_general_ci
我要补充的另一件事是,即使你知道你的应用程序只支持英语,它可能仍然需要处理人们的名字,这些人的名字通常可能包含其他语言中使用的字符,在这些语言中,正确排序同样重要。对所有事情都使用 Unicode 规则有助于让您高枕无忧,因为非常聪明的 Unicode 人员已经非常努力地使排序正常工作。
零件的含义
首先,用于不区分大小写的排序和比较。这意味着它适用于文本数据,大小写并不重要。其他类型的排序规则是(区分大小写)用于大小写很重要的文本数据,以及 ,用于编码需要匹配的逐位排序规则,适用于真正编码的二进制数据字段(例如,包括 Base64)。区分大小写的排序会导致一些奇怪的结果,区分大小写的比较可能会导致重复的值仅在字母大小写方面有所不同,因此区分大小写的排序规则对文本数据来说已经失宠了 - 如果大小写对你来说很重要,那么其他可忽略的标点符号等可能也很重要,二进制排序规则可能更合适。ci
cs
bin
接下来,或指特定的排序和比较规则 - 特别是文本的规范化或比较方式。utf8mb4 字符编码有许多不同的规则集,其中 和 be 是两个试图在所有可能的语言中很好地工作,而不是一种特定的语言。这两套规则之间的差异是这个答案的主题。请注意,它使用 Unicode 4.0 中的规则。最新版本的MySQL和MariaDB使用Unicode 5.2中的规则添加规则集,MySQL 8.x使用Unicode 9.0中的规则添加(删除“unicode_”部分)。unicode
general
unicode
general
unicode
unicode_520
0900
最后,当然是内部使用的字符编码。在这个答案中,我只谈论基于 Unicode 的编码。utf8mb4
评论
utf8_general_ci
utf8_unicode_ci
utf8
utf8mb4_unicode_520_ci
这篇文章很好地描述了它。
简而言之:使用 Unicode 标准中定义的 Unicode 排序规则算法,而是一种更简单的排序顺序,会导致“不太准确”的排序结果。utf8_unicode_ci
utf8_general_ci
评论
utf8_unicode_ci
utf8_general_ci
我想知道使用 和 之间的性能差异是什么,但我没有在互联网上找到任何基准测试,所以我决定自己创建基准测试。utf8_general_ci
utf8_unicode_ci
我创建了一个非常简单的表,其中包含 500,000 行:
CREATE TABLE test(
ID INT(11) DEFAULT NULL,
Description VARCHAR(20) DEFAULT NULL
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;
然后,我通过运行以下存储过程用随机数据填充它:
CREATE PROCEDURE randomizer()
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE random CHAR(20) ;
theloop: loop
SET random = CONV(FLOOR(RAND() * 99999999999999), 20, 36);
INSERT INTO test VALUES (i+1, random);
SET i=i+1;
IF i = 500000 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END
然后,我创建了以下存储过程来对简单、和排序( )进行基准测试:SELECT
SELECT
LIKE
SELECT
ORDER BY
CREATE PROCEDURE benchmark_simple_select()
BEGIN
DECLARE i INT DEFAULT 0;
theloop: loop
SELECT *
FROM test
WHERE Description = 'test' COLLATE utf8_general_ci;
SET i = i + 1;
IF i = 30 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END;
CREATE PROCEDURE benchmark_select_like()
BEGIN
DECLARE i INT DEFAULT 0;
theloop: loop
SELECT *
FROM test
WHERE Description LIKE '%test' COLLATE utf8_general_ci;
SET i = i + 1;
IF i = 30 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END;
CREATE PROCEDURE benchmark_order_by()
BEGIN
DECLARE i INT DEFAULT 0;
theloop: loop
SELECT *
FROM test
WHERE ID > FLOOR(1 + RAND() * (400000 - 1))
ORDER BY Description COLLATE utf8_general_ci LIMIT 1000;
SET i = i + 1;
IF i = 10 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END;
在上面的存储过程中使用了排序规则,但当然在测试期间,我同时使用了 和 。utf8_general_ci
utf8_general_ci
utf8_unicode_ci
我为每个排序规则调用每个存储过程 5 次(5 次,5 次),然后计算平均值。utf8_general_ci
utf8_unicode_ci
我的结果是:
benchmark_simple_select()
- 含:9,957 ms
utf8_general_ci
- 10,271 ms
utf8_unicode_ci
在这个基准中,使用速度比 3.2% 慢。utf8_unicode_ci
utf8_general_ci
benchmark_select_like()
- 11,441 毫秒
utf8_general_ci
- 12,811 ms
utf8_unicode_ci
在此基准测试中,使用速度比 12% 慢。utf8_unicode_ci
utf8_general_ci
benchmark_order_by()
- 含:11,944 ms
utf8_general_ci
- 12,887 毫秒
utf8_unicode_ci
在这个基准中,使用速度比7.9%慢。utf8_unicode_ci
utf8_general_ci
评论
utf8_general_ci
CONV(FLOOR(RAND() * 99999999999999), 20, 36)
Description = 'test' COLLATE ...
Description LIKE 'test%' COLLATE ...
简而言之:
如果您需要更好的排序顺序 - 使用(这是首选方法),utf8_unicode_ci
但是,如果您对性能完全感兴趣 - 使用 ,但要知道它有点过时了。utf8_general_ci
性能方面的差异非常小。
评论
一些细节 (PL)
正如我们在这里读到的(Peter Gulutzan),排序/比较波兰字母“Ł”(L with stroke - html esc: ) (小写:“ł” - html esc: ) - 我们有以下假设:Ł
ł
utf8_polish_ci Ł greater than L and less than M
utf8_unicode_ci Ł greater than L and less than M
utf8_unicode_520_ci Ł equal to L
utf8_general_ci Ł greater than Z
在波兰语中,字母在字母之后和之前。这种编码没有一个是好是坏 - 这取决于您的需求。Ł
L
M
评论
根据这篇文章,当使用 utf8mb4_general_ci 代替 utf8mb4_unicode_ci 时,MySQL 5.7 具有相当大的性能优势:https://www.percona.com/blog/2019/02/27/charset-and-collation-settings-impact-on-mysql-performance/
评论
排序和字符匹配有两大区别:
排序:
utf8mb4_general_ci
删除所有重音符号并逐个排序,这可能会产生不正确的排序结果。utf8mb4_unicode_ci
排序准确。
字符匹配
它们以不同的方式匹配角色。
例如,in you have , but in it holds .utf8mb4_unicode_ci
i != ı
utf8mb4_general_ci
ı=i
例如,假设您有一行 .然后name="Yılmaz"
select id from users where name='Yilmaz';
如果 并置 ,将返回该行,但如果它与它并置,则不会返回该行!utf8mb4_general_ci
utf8mb4_unicode_ci
另一方面,我们有那个,其中不是这种情况。所以想象一下,你有一行,那么a=ª
ß=ss
utf8mb4_unicode_ci
utf8mb4_general_ci
name="ªßi"
select id from users where name='assi';
如果 collocation 为 ,则返回该行,但如果 collocation 设置为 ,则不会返回该行。utf8mb4_unicode_ci
utf8mb4_general_ci
可以在此处找到每个搭配的完整匹配列表。
上述评论表明没有理由使用 .然而,对于日本人来说,这可能不是真的。utf8_general*
MariaDB不可用,因此您必须使用unicode或常规选项之一。但是,对浊音和无浊音等一视同仁。例如,びよういん(美容师)被视为等于びょういん(医院)。这显然是不正确的行为。utf8mb4_ja_0900_as_cs
unicode
> select strcmp('が', 'か' collate utf8mb4_unicode_ci); #0
> strcmp('びよういん', 'びょういん' collate utf8mb4_unicode_520_ci); #0
而一般给出
> select strcmp('が', 'か' collate utf8mb4_general_ci); #1
换句话说,unicode 对浊音假名和无浊音假名的处理方式相同。Imo,这是不可取的。
编辑:最好使用较新版本的MariaDB上可用的排序规则,并正确处理上述排序规则。uca1400_ai_cs
评论
utf8[mb4]_unicode_ci
utf8[mb4]_unicode_520_ci
utf8mb4_0900_ai_ci