utf8_general_ci
和之间utf8_unicode_ci
,在效果方面是否存在差异?
utf8[mb4]_unicode_ci
,您可能utf8[mb4]_unicode_520_ci
会更喜欢。
utf8mb4_0900_ai_ci
。
utf8_general_ci
和之间utf8_unicode_ci
,在效果方面是否存在差异?
utf8[mb4]_unicode_ci
,您可能utf8[mb4]_unicode_520_ci
会更喜欢。
utf8mb4_0900_ai_ci
。
Answers:
这两个归类均适用于UTF-8字符编码。区别在于文本的排序和比较方式。
注意:在MySQL中,您必须使用utf8mb4
而不是utf8
。令人困惑的是,utf8
是早期MySQL版本中有缺陷的UTF-8实现,仅用于向后兼容。固定版本的名称为utf8mb4
。
注意:较新版本的MySQL已更新了Unicode排序规则,可以在名称下使用,例如 utf8mb4_0900_ai_ci
基于Unicode 9.0的等效规则-且没有等效 _general
变体。现在阅读此书的人们可能应该使用这些较新的排序规则之一,而不是 _unicode
or _general
。如果您可以使用一种新的排序规则来代替,那么下面编写的大部分内容都将不再有意义。
关键差异
utf8mb4_unicode_ci
基于用于通用排序和比较的官方Unicode规则,该规则可以在多种语言中进行准确排序。
utf8mb4_general_ci
是一组简化的排序规则,旨在尽力而为,同时采用许多旨在提高速度的捷径。它不遵循Unicode规则,在某些情况下(例如,使用特定语言或字符时)会导致不希望的排序或比较。
在现代服务器上,这种性能提升几乎可以忽略不计。它是在服务器仅具有当今计算机CPU性能的一小部分的时候设计的。
utf8mb4_unicode_ci
超过的好处utf8mb4_general_ci
utf8mb4_unicode_ci
使用Unicode规则进行排序和比较,它使用相当复杂的算法对多种语言和使用多种特殊字符进行正确排序。这些规则需要考虑到特定于语言的约定。并不是每个人都按照我们所谓的“字母顺序”对字符进行排序。
就拉丁(即“欧洲”)语言而言,Unicode排序与utf8mb4_general_ci
MySQL中的简化排序之间没有太大差异,但仍然存在一些差异:
例如,Unicode归类对使用这些字符的人通常会希望将“ß”(如“ ss”)和“Œ”(如“ OE”)进行utf8mb4_general_ci
排序,而将它们排序为单个字符(大概分别像“ s”和“ e”一样) 。
一些Unicode字符被定义为可忽略,这意味着它们不应该计入排序顺序,而比较应该继续到下一个字符。 utf8mb4_unicode_ci
正确处理这些。
在非拉丁语言(例如亚洲语言或具有不同字母的语言)中,Unicode排序和简化排序之间可能会有更多差异utf8mb4_general_ci
。的适用性utf8mb4_general_ci
将在很大程度上取决于所使用的语言。对于某些语言,这将是远远不够的。
你应该用什么?
几乎肯定没有理由再使用utf8mb4_general_ci
了,因为我们已经落后了CPU速度足够低而性能差异很重要的地步。您的数据库几乎肯定会受到其他瓶颈的限制。
过去,有人建议使用,utf8mb4_general_ci
除非准确的分类变得足够重要以证明性能成本合理。今天,这种性能成本几乎消失了,开发人员正在更加认真地对待国际化。
有一种观点认为,如果速度对您而言比准确性更重要,那么您可能根本不做任何排序。如果不需要精确的算法,则可以使算法更快。因此,这utf8mb4_general_ci
是一种折衷方案,出于速度原因可能不需要,而且出于准确性原因也可能不合适。
我要补充的另一件事是,即使您知道您的应用程序仅支持英语,它仍可能需要处理人的名字,该名字通常可以包含其他语言中使用的字符,在这些语言中正确排序同样重要。对所有内容使用Unicode规则有助于让您放心,非常聪明的Unicode人员为使排序正常工作而进行了非常努力的工作。
零件是什么意思
首先,ci
是不区分大小写的排序和比较。这意味着它适用于文本数据,并且大小写并不重要。其他排序规则是cs
(区分大小写的)区分大小写的文本数据bin
,对于需要匹配的编码,一点一点的排序,这适用于真正编码二进制数据的字段(例如, Base64)。区分大小写的排序会导致一些奇怪的结果,并且区分大小写的比较可能导致重复值仅在字母大小写上有所不同,因此区分大小写的排序规则对文本数据不受欢迎-如果大小写对您而言很重要,则标点符号会被忽略等等也可能很重要,二进制排序可能更合适。
接下来,unicode
或general
指的是特定的排序和比较规则-特别是规范化或比较文本的方式。有对utf8mb4字符编码许多不同的规则集,以unicode
和general
为两块尝试工作以及在所有可能的语言,而不是一个具体的一个。这两组规则之间的差异是此答案的主题。请注意,它unicode
使用Unicode 4.0中的规则。MySQL的最新版本unicode_520
使用Unicode 5.2中的规则添加规则集,并0900
使用Unicode 9.0中的规则添加(删除“ unicode_”部分)。
最后,utf8mb4
当然是内部使用的字符编码。在这个答案中,我仅谈论基于Unicode的编码。
utf8_general_ci
:它根本不起作用。这可以追溯到50年前的ASCII加密的糟糕历史。如果没有UCD的折叠大小写映射,则Unicode区分大小写的匹配将无法完成。例如,“Σίσυφος”中包含三个不同的西格玛;或者“TSCHüẞ”的小写字母是“tschüβ”,而“tschüβ”的大写字母是“TSCHÜSS”。您可能是正确的,也可以是快速的。因此,您必须使用utf8_unicode_ci
,因为如果您不关心正确性,那么使其无限快速地变得微不足道。
"か" == "が"
或的情况"ǽ" == "æ"
。对于排序来说,这是有道理的,但在通过相等选择或处理唯一索引时可能会令人惊讶-bugs.mysql.com/bug.php?id=16526
utf8mb4
是唯一正确的选择。将utf8
您困在某些仅MySQL的3字节UTF8变体中,只有MySQL(和MariaDB)知道该怎么做。世界其他地区正在使用UTF8,每个字符最多可包含4个字节。MySQL开发人员将自己的自制编码错误命名,utf8
并且为了不破坏向后兼容性,他们现在必须将真正的UTF8称为utf8mb4
。
我想知道使用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
然后,我创建了以下存储过程,以对simple SELECT
,SELECT
和LIKE
和sorting(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次utf8_general_ci
和5次utf8_unicode_ci
),然后计算平均值。
我的结果是:
benchmark_simple_select()
utf8_general_ci
:9,957毫秒 utf8_unicode_ci
:10,271毫秒 在此基准测试中,使用utf8_unicode_ci
速度慢于utf8_general_ci
3.2%。
benchmark_select_like()
utf8_general_ci
:11,441毫秒 utf8_unicode_ci
:12,811毫秒 在此基准测试中,使用utf8_unicode_ci
速度要慢utf8_general_ci
12%。
benchmark_order_by()
utf8_general_ci
:11,944毫秒 utf8_unicode_ci
:12,887毫秒 在此基准测试中,使用utf8_unicode_ci
速度比utf8_general_ci
7.9%慢。
utf8_general_ci
太小,不值得使用。
CONV(FLOOR(RAND() * 99999999999999), 20, 36)
仅生成ASCII,而不会生成由归类算法处理的Unicode字符。2)Description = 'test' COLLATE ...
并且Description LIKE 'test%' COLLATE ...
仅在运行时处理单个字符串(“测试”),不是吗?3)在实际的应用程序中,排序时使用的列可能会被索引,并且在具有实际非ASCII文本的不同排序规则上的索引速度可能会有所不同。
这篇文章很好地描述了它。
简而言之:utf8_unicode_ci使用Unicode标准中定义的Unicode排序算法,而utf8_general_ci是更简单的排序顺序,导致“不太准确”的排序结果。
utf8_unicode_ci
并假装另一个不存在。
utf8_general_ci
可能对您有所帮助
参见mysql手册的Unicode字符集部分:
对于任何Unicode字符集,使用_general_ci归类执行的操作都比使用_unicode_ci归类进行的操作要快。例如,与utf8_unicode_ci的比较相比,utf8_general_ci归类的比较更快,但正确性稍差。原因是utf8_unicode_ci支持诸如扩展之类的映射。也就是说,当一个字符比较等于其他字符的组合时。例如,在德语和其他一些语言中,“ß”等于“ ss”。utf8_unicode_ci还支持收缩和可忽略字符。utf8_general_ci是旧版归类,不支持扩展,收缩或可忽略的字符。它只能在字符之间进行一对一比较。
综上所述,与应实现整个标准的utf_unicode_ci相比,utf_general_ci使用的比较集更小且不正确(根据标准)。general_ci设置将更快,因为需要执行的计算更少。
utf8_unicode_ci
并假装越野车损坏的版本不存在。
0
和之间的实数,而1
不是布尔值。:) EG在边界框中选择地理位置是“附近的点”的近似值,不如计算该点与参考点之间的距离并对其进行过滤。但两者都是近似值,实际上,完全正确性是无法实现的。参见海岸线悖论和IEEE 754
1/3
简而言之:
如果您需要更好的排序顺序-使用utf8_unicode_ci
(这是首选方法),
但是,如果您对性能完全感兴趣,请使用utf8_general_ci
,但是知道它有点过时了。
在性能方面的差异很小。
正如我们在此处阅读的内容(彼得·古鲁赞(Peter Gulutzan)),波兰语字母“Ł”(带有笔画的L-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
排序准确。字符匹配
它们以不同的方式匹配字符。
例如,utf8mb4_unicode_ci
您拥有i != ı
,但utf8mb4_general_ci
拥有ı=i
。
例如,假设您有一行name="Yılmaz"
。然后
select id from users where name='Yilmaz';
如果collocation为utf8mb4_general_ci
,将返回该行,但是如果与之并置,utf8mb4_unicode_ci
则不会返回该行!
在另一方面,我们有a=ª
和ß=ss
在utf8mb4_unicode_ci
其不在的情况下utf8mb4_general_ci
。因此,假设您与有一行name="ªßi"
,然后
select id from users where name='assi';
如果collocation为utf8mb4_unicode_ci
,将返回行,但如果collocation设置为,则不返回行utf8mb4_general_ci
。
可以在这里找到每种搭配的完整比赛清单。
根据这篇文章,使用utf8mb4_general_ci代替utf8mb4_unicode_ci时,在MySQL 5.7上有相当大的性能优势:https ://www.percona.com/blog/2019/02/27/charset-and-collation-settings-impact -关于mysql-performance /