utf8_general_ci和utf8_unicode_ci有什么区别?

utf8_general_ciutf8_unicode_ci ,在性能方面有什么区别吗?

这两个归类都是用于UTF-8字符编码的。 差异在于文本如何sorting和比较。

注意:由于MySQL 5.5.3,你应该使用utf8mb4而不是utf8 它们都是指UTF-8编码,但是较早的utf8有一个MySQL特有的限制,防止使用大于0xFFFD的字符。

  • 准确性

    utf8mb4_unicode_ci是基于Unicode标准进行sorting和比较的,可以用很多种语言准确地sorting。

    utf8mb4_general_ci无法实现所有的Unicodesorting规则,这会在某些情况下导致不合需要的sorting,例如在使用特定的语言或字符时。

  • 性能

    utf8mb4_general_ci在比较和sorting上更快,因为它需要一些与性能相关的快捷键。

    在现代服务器上,这种性能提升将几乎可以忽略不计。 当时的服务器只有当今计算机CPU性能的一小部分。

    使用Unicode规则进行sorting和比较的utf8mb4_unicode_ci采用了相当复杂的algorithm,可以在各种语言和各种特殊字符中正确sorting。 这些规则需要考虑到特定于语言的惯例; 不是每个人都按照我们所说的“按字母顺序sorting”来分类他们的angular色。

就拉丁语(即“欧洲”)语言而言,在Unicode中sorting和在MySQL中简化的utf8mb4_general_cisorting没有太大的区别,但是还是有一些区别的:

  • 例如,Unicodesorting规则将“ß”类似“ss”和“Œ”类似于“OE”,因为使用这些字符的人通常会想要,而utf8mb4_general_ci它们分类为单个字符(可能分别为“s”和“e” )。

  • 一些Unicode字符被定义为可忽略的,这意味着它们不应该被计算为sorting顺序,并且比较应该移动到下一个字符。 utf8mb4_unicode_ci正确处理这些。

在非拉丁语言中,如亚洲语言或具有不同字母的语言,Unicodesorting和简化的utf8mb4_general_cisorting之间可能会有很多差异。 utf8mb4_general_ci的适用性在utf8mb4_general_ci取决于所使用的语言。 对于某些语言来说,这将是相当不足的。

你应该使用什么?

几乎肯定没有理由再使用utf8mb4_general_ci了,因为我们已经放弃了CPU速度足够低以至于性能差异很重要的地步。 你的数据库几乎肯定会受到其他瓶颈的限制。

性能上的差异只能在极其特殊的情况下才能衡量,如果这就是你,你可能已经知道了。 如果你的sorting很慢,几乎在所有情况下,这将是你的索引/查询计划的一个问题。 更改您的sorting规则function不应该排在要排除故障的列表中。

过去,有些人build议使用utf8mb4_general_ci除非准确的sorting将足够重要,以certificate性能成本。 如今,这种性能成本几乎消失,开发人员正在更加严肃地对待国际化。

我还要补充的另一件事是,即使你知道你的应用程序只支持英语,它仍然需要处理人们的姓名,这些姓名通常可以包含其他语言中使用的字符,正确sorting也同样重要。 对所有内容使用Unicode规则有助于让人高枕无忧,非常聪明的Unicode人员已经非常努力地进行分类工作。

我想知道使用utf8_general_ci和utf8_unicode_ci之间的性能差异,但是我没有在Internet上find任何基准,所以我决定自己创build基准。

我创build了一个包含500000行的非常简单的表格:

 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 

然后,我创build了以下存储过程来对简单的SELECT进行基准testing,使用LIKE进行SELECT和sorting(使用ORDER BY进行SELECT):

 CREATE 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_cisorting规则,但是在testing过程中,我使用了utf8_general_ci和utf8_unicode_ci。

我为每个归类调用每个存储过程5次(utf8_general_ci为5次,utf8_unicode_ci为5次),然后计算平均值。

我的结果是:

benchmark_simple_select()与utf8_general_ci:9957毫秒
benchmark_simple_select()与utf8_unicode_ci:10271 ms
在这个基准testing中,使用utf8_unicode_ci的速度比utf8_general_ci慢3.2个百分点。

benchmark_select_like()与utf8_general_ci:11441毫秒
benchmark_select_like()与utf8_unicode_ci:12811毫秒
在这个基准testing中,使用utf8_unicode_ci的速度比utf8_general_ci慢12%。

benchmark_order_by()与utf8_general_ci:11944毫秒
benchmark_order_by()与utf8_unicode_ci:12887毫秒
在这个基准testing中,使用utf8_unicode_ci比utf8_general_ci慢7.9%。

这篇文章描述得非常好。

简而言之:utf8_unicode_ci使用Unicode标准中定义的Unicodesortingalgorithm,而utf8_general_ci是更简单的sorting顺序,导致sorting结果“不太精确”。

请参阅mysql手册中的Unicode字符集部分:

对于任何Unicode字符集,使用_general_cisorting规则执行的操作比_unicode_cisorting规则更快。 例如,比较utf8_general_cisorting比较比utf8_unicode_ci更快,但是稍微不正确。 原因是utf8_unicode_ci支持扩展等映射。 也就是说,当一个字符比较等于其他字符的组合。 例如,在德语和其他一些语言中,“ß”等于“ss”。 utf8_unicode_ci也支持收缩和可忽略的字符。 utf8_general_ci是不支持扩展,缩小或可忽略字符的传统sorting规则。 它只能对字符进行一对一的比较。

所以总结一下,utf_general_ci使用比utf_unicode_ci更小,更不正确的(根据标准)比较集合,它应该实现整个标准。 general_ci集合会更快,因为计算量less。

简言之:

如果你需要更好的sorting顺序 – 使用utf8_unicode_ci (这是首选的方法),

但是如果你对性能完全感兴趣 – 使用utf8_general_ci ,但知道它有点过时了。

性能方面的差异很小。

有图表整理字符: http : //collat​​ion-charts.org/mysql60/mysql604.utf8_general_ci.european.html和http://collat​​ion-charts.org/mysql60/mysql604.utf8_unicode_ci.european.html

为了将值“é”和“e”保存在唯一列中,您应该将其归类设置为“ut8_bin”,以避免重复错误。

我没有看到在日常使用中使用'utf8_unicode_ci'的好处。