utf8_general_ci 和 utf8_unicode_ci 有什么区别?

What's the difference between utf8_general_ci and utf8_unicode_ci?

提问人:KahWee Teng 提问时间:4/20/2009 最后编辑:simhumilecoKahWee Teng 更新时间:12/25/2022 访问量:607781

问:

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

MySQL Unicode UTF-8 归类 字符集

评论

3赞 unor 8/29/2012
另请参阅 stackoverflow.com/questions/1036454/...
9赞 Rick James 1/27/2016
如果你喜欢,你可能会喜欢更多。utf8[mb4]_unicode_ciutf8[mb4]_unicode_520_ci
11赞 Rick James 1/5/2019
更好的是 8.0 的默认值。utf8mb4_0900_ai_ci
0赞 Rick James 2/7/2021
8.0 显著加快了 utf8 的比较速度。(可能是 utf8/utf8mb4 的所有排序规则)
2赞 Gazzer 12/25/2022
utf8_unicode_ci日语坏了。bugs.mysql.com/bug.php?id=79977 将びよういん(美发沙龙)和びょういん(医院)视为同一个词。520 选项也是如此。

答:

14赞 Dana the Sane 4/20/2009 #1

请参阅 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集会更快,因为要执行的计算更少。

评论

20赞 tchrist 3/16/2012
没有“稍微不那么正确”这样的事情。正确性是一个布尔特征;它不承认程度的修饰语。只需使用并假装有缺陷的损坏版本不存在。utf8_unicode_ci
2赞 Steve Hibbert 1/26/2014
我在让 5.6.15 采用collation_connection设置时遇到了问题,事实证明您必须在 SET 行中传递它,例如“SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci”。感谢Mathias Bynens的解决方案,这是他非常有用的指南: mathiasbynens.be/notes/mysql-utf8mb4
6赞 Anthony 11/19/2015
@tchrist 说正确性是布尔值的问题在于,它没有考虑到不依赖于绝对正确性的情况。你的基本观点不是无效的,我也不是试图支持general_ci的好处,但你关于正确性的一般陈述很容易被推翻。在我的职业中,我每天都这样做。撇开喜剧不谈,斯图尔特在这里说得很有道理。
6赞 Stijn de Witt 6/15/2016
通过地理定位或游戏开发,我们一直在权衡正确性与性能。当然,正确性是介于 和 之间的实数,而不是布尔值。:)例如,在边界框中选择地理点是“附近点”的近似值,这不如计算点和参考点之间的距离并对其进行过滤。但两者都是近似值,事实上,完全正确性大多是无法实现的。查看海岸线悖论IEEE 75401
4赞 Stijn de Witt 6/15/2016
TL;DR:请提供一个程序来打印正确的结果1/3
1992赞 thomasrutter 4/20/2009 #2

对于那些在 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_ciutf8mb4_general_ci

你应该使用什么?

几乎可以肯定的是,没有理由再使用,因为我们已经忽略了CPU速度足够低的点,因此性能差异很重要。几乎可以肯定的是,您的数据库将受到其他瓶颈的限制。utf8mb4_general_ci

过去,有些人建议使用,除非准确排序足够重要,足以证明性能成本是合理的。如今,这种性能成本几乎消失了,开发人员正在更加认真地对待国际化。utf8mb4_general_ci

有一种观点认为,如果速度对你来说比准确性更重要,那么你还不如根本不做任何排序。如果您不需要算法的准确性,那么使算法更快是微不足道的。因此,出于速度原因,可能不需要这种折衷方案,也可能不适合出于准确性原因。utf8mb4_general_ci

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

零件的含义

首先,用于不区分大小写的排序和比较。这意味着它适用于文本数据,大小写并不重要。其他类型的排序规则是(区分大小写)用于大小写很重要的文本数据,以及 ,用于编码需要匹配的逐位排序规则,适用于真正编码的二进制数据字段(例如,包括 Base64)。区分大小写的排序会导致一些奇怪的结果,区分大小写的比较可能会导致重复的值仅在字母大小写方面有所不同,因此区分大小写的排序规则对文本数据来说已经失宠了 - 如果大小写对你来说很重要,那么其他可忽略的标点符号等可能也很重要,二进制排序规则可能更合适。cicsbin

接下来,或指特定的排序和比较规则 - 特别是文本的规范化或比较方式。utf8mb4 字符编码有许多不同的规则集,其中 和 be 是两个试图在所有可能的语言中很好地工作,而不是一种特定的语言。这两套规则之间的差异是这个答案的主题。请注意,它使用 Unicode 4.0 中的规则。最新版本的MySQL和MariaDB使用Unicode 5.2中的规则添加规则集,MySQL 8.x使用Unicode 9.0中的规则添加(删除“unicode_”部分)。unicodegeneralunicodegeneralunicodeunicode_5200900

最后,当然是内部使用的字符编码。在这个答案中,我只谈论基于 Unicode 的编码。utf8mb4

评论

266赞 tchrist 3/16/2012
@KahWeeTeng 你永远不应该使用:它根本不起作用。这是对五十年前 ASCII 傀儡的糟糕过去的倒退。如果没有UCD的折叠大小写映射,就无法完成Unicode不区分大小写的匹配。例如,“Σίσυφος”有三个不同的西格玛;或者“TSCHüẞ”的小写字母是“tschüβ”,但“tschüβ”的大写字母是“TSCHÜSS”。你可以是对的,也可以是快的。因此,您必须使用 ,因为如果您不关心正确性,那么让它无限快是微不足道的。utf8_general_ciutf8_unicode_ci
1赞 thomasrutter 7/10/2021
@BrianTristamWilliams排序规则是指文本比较和排序的工作方式。“bin”作为排序规则意味着它只是一个二进制比较:不会尝试适应任何书面语言约定,它将纯粹在数据位上进行比较。
1赞 cazort 8/27/2021
@nightcoder提到的性能提升在我看来是可以忽略不计的。我不会忽视 3% 的收益,12% 的收益更大,尤其是当任何数据库管理员做出数十个甚至数百个对性能影响的选择时,它们加起来。更重要的是,有时正确性并不重要。我的大多数数据库都需要容纳非基本拉丁编码的 unicode 字符,但很少需要按这些字符准确排序,事实上,我想不出在我整个 20+ 年的职业生涯中需要这个的实例。
3赞 jchook 5/14/2022
@thomasrutter谢谢。我还看到 MariaDB 显然计划跳过 utf8mb4_0900_* 并升级到 utf8mb4_1400_*
2赞 Guildenstern 7/25/2023
“对于那些在 2020 年或以后仍然遇到这个问题的人,[...]例如,utf8_unicode_520_ci。2023 年的你好。鉴于字符集已被弃用,这不应该是吗?utf8utf8mb4_unicode_520_ci
58赞 Michael Madsen 1/1/2010 #3

这篇文章很好地描述了它。

简而言之:使用 Unicode 标准中定义的 Unicode 排序规则算法,而是一种更简单的排序顺序,会导致“不太准确”的排序结果。utf8_unicode_ciutf8_general_ci

评论

18赞 tchrist 3/16/2012
如果你不关心正确性,那么让任何算法无限快都是微不足道的。只需使用并假装另一个不存在。utf8_unicode_ci
3赞 Shelvacu 1/27/2016
@tchrist但如果你在乎正确性和速度之间的某种平衡,可能适合你utf8_general_ci
5赞 Stijn de Witt 6/15/2016
@tchrist 永远不要成为游戏程序员;)
1赞 Rick James 9/28/2017
@onassar - MySQL 8.0 声称显着提高了所有排序规则的性能。
207赞 nightcoder 3/2/2013 #4

我想知道使用 和 之间的性能差异是什么,但我没有在互联网上找到任何基准测试,所以我决定自己创建基准测试。utf8_general_ciutf8_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

然后,我创建了以下存储过程来对简单、和排序( )进行基准测试:SELECTSELECTLIKESELECTORDER 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_ciutf8_general_ciutf8_unicode_ci

我为每个排序规则调用每个存储过程 5 次(5 次,5 次),然后计算平均值。utf8_general_ciutf8_unicode_ci

我的结果是:

benchmark_simple_select()

  • 含:9,957 msutf8_general_ci
  • 10,271 msutf8_unicode_ci

在这个基准中,使用速度比 3.2% 慢。utf8_unicode_ciutf8_general_ci

benchmark_select_like()

  • 11,441 毫秒utf8_general_ci
  • 12,811 msutf8_unicode_ci

在此基准测试中,使用速度比 12% 慢。utf8_unicode_ciutf8_general_ci

benchmark_order_by()

  • 含:11,944 msutf8_general_ci
  • 12,887 毫秒utf8_unicode_ci

在这个基准中,使用速度比7.9%慢。utf8_unicode_ciutf8_general_ci

评论

22赞 RandomSeed 9/15/2013
不错的基准,感谢分享。我得到了合理的相似数字(Windows 上的 MySQL v5.6.12):10%、4%、8%。我同意:性能提升太小了,不值得使用。utf8_general_ci
12赞 Halil Özgür 10/13/2014
1) 但是,根据定义,这个基准测试不应该为两个排序规则生成类似的结果吗?我的意思是只生成 ASCII,而不生成排序规则算法要处理的 Unicode 字符。2)并且只在运行时处理单个字符串(“测试”),不是吗?3) 在实际应用中,排序中使用的列可能会被索引,并且使用真正的非 ASCII 文本的不同排序规则的索引速度可能会有所不同。CONV(FLOOR(RAND() * 99999999999999), 20, 36)Description = 'test' COLLATE ...Description LIKE 'test%' COLLATE ...
2赞 Tomasz Gandor 4/14/2015
@HalilÖzgür - 你的观点部分错误。我想这不是关于 ASCII 之外的代码点值(general_ci可以正确处理),而是关于特定功能,例如将写成“Umleaute”的变音符号或一些这样的微妙之处。
2赞 cazort 8/27/2021
因此,虽然这些性能提升看起来很引人注目,但我想知道这是否适用于真实世界的数据。您正在用随机字符填充这些字段,但在现实世界中,数据具有更多的结构,并且结构与排序相关。我的大多数数据库中绝大多数字符都是采用基本拉丁语编码的,少量其他字符通常位于此处或那里的字段中。目前尚不清楚在这些情况下是否会有任何性能提升。会有吗?我很好奇在我的一些真实数据上运行它。
11赞 simhumileco 3/6/2017 #5

简而言之:

如果您需要更好的排序顺序 - 使用(这是首选方法),utf8_unicode_ci

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

性能方面的差异非常小。

评论

2赞 thomasrutter 2/12/2020
两者现在都已经过时了 - 有关更多信息,请参阅公认的答案
12赞 Kamil Kiełczewski 11/20/2018 #6

一些细节 (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

在波兰语中,字母在字母之后和之前。这种编码没有一个是好是坏 - 这取决于您的需求。ŁLM

评论

0赞 konieckropka 3/7/2023
Świetne spostrzeżenie.Dzięki wielkie za to!
1赞 DavidH 9/23/2019 #7

根据这篇文章,当使用 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/

评论

0赞 cazort 8/28/2021
同样重要的是要注意,链接到的分析观察到MySQL 8.0没有任何显着的好处。因此,这个问题的答案似乎高度依赖于版本。
12赞 Adam 12/7/2019 #8

排序和字符匹配有两大区别:

排序

  • utf8mb4_general_ci删除所有重音符号并逐个排序,这可能会产生不正确的排序结果。
  • utf8mb4_unicode_ci排序准确。

字符匹配

它们以不同的方式匹配角色。

例如,in you have , but in it holds .utf8mb4_unicode_cii != ıutf8mb4_general_ciı=i

例如,假设您有一行 .然后name="Yılmaz"

select id from users where name='Yilmaz';

如果 并置 ,将返回该行,但如果它与它并置,则不会返回该行!utf8mb4_general_ciutf8mb4_unicode_ci

另一方面,我们有那个,其中不是这种情况。所以想象一下,你有一行,那么a=ªß=ssutf8mb4_unicode_ciutf8mb4_general_ciname="ªßi"

select id from users where name='assi';

如果 collocation 为 ,则返回该行,但如果 collocation 设置为 ,则不会返回该行。utf8mb4_unicode_ciutf8mb4_general_ci

可以在此处找到每个搭配的完整匹配列表。

1赞 Gazzer 12/25/2022 #9

上述评论表明没有理由使用 .然而,对于日本人来说,这可能不是真的。utf8_general*

MariaDB不可用,因此您必须使用unicode或常规选项之一。但是,对浊音和无浊音等一视同仁。例如,びよういん(美容师)被视为等于びょういん(医院)。这显然是不正确的行为。utf8mb4_ja_0900_as_csunicode

> 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