utf8_general_ci
和utf8_unicode_ci
之间,在性能方面是否有任何区别?
utf8_general_ci
和utf8_unicode_ci
之间,在性能方面是否有任何区别?
utf8_unicode_520_ci
。
所有这些排序规则都适用于UTF-8字符编码。差异在于如何对文本进行排序和比较。
_unicode_ci
和_general_ci
是两种不同的规则集,用于根据我们的期望对文本进行排序和比较。MySQL的新版本也引入了新的规则集,例如基于Unicode 5.2的_unicode_520_ci
或基于Unicode 9.0的MySQL 8.x特定_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的排序和比较规则,在广泛的语言和使用广泛的特殊字符时采用相当复杂的算法以实现正确的排序。这些规则需要考虑特定于语言的惯例;并非所有人都按照我们所说的“字母顺序”对其字符进行排序。
就拉丁(即“欧洲”)语言而言,在MySQL中,Unicode排序和简化的utf8mb4_general_ci
排序之间没有太大的区别,但仍然存在一些差异:
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和MariaDB的最新版本添加了规则集unicode_520
,使用Unicode 5.2的规则,而MySQL 8.x添加了0900
(删除“unicode_”部分),使用Unicode 9.0的规则。utf8mb4
当然是内部使用的字符编码。在本答案中,我只讨论基于Unicode的编码。utf8_general_ci
:它根本无法正常工作。它是50年前ASCII愚蠢时代的回归。Unicode大小写不敏感匹配不能在没有UCD的foldcase映射的情况下完成。例如,“Σίσυφος”有三个不同的sigma;或者“TSCHüẞ”的小写形式是“tschüβ”,但“tschüβ”的大写形式是“TSCHÜSS”。你可以正确,也可以快速。因此,你必须使用utf8_unicode_ci
,因为如果你不关心正确性,那么把它变得无限快速是微不足道的。 - tchristutf8mb4_0900_*
并升级到utf8mb4_1400_*
。 (请注意,这是机器翻译,仅供参考) - jchookutf8
字符集已被弃用,这应该改为utf8mb4_unicode_520_ci
,不是吗? - Guildenstern我想知道在使用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
、带有LIKE
的SELECT
以及排序(ORDER BY
的SELECT
):
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
两种规则。utf8_general_ci
分别调用5次,utf8_unicode_ci
分别调用5次),然后计算了平均值。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
带来的性能提升实在是太小了,不值得使用。 - RandomSeedCONV(FLOOR(RAND() * 99999999999999), 20, 36)
只会生成ASCII字符,没有Unicode字符需要由排序算法处理。
2)Description = 'test' COLLATE ...
和Description LIKE 'test%' COLLATE...
在运行时只处理单个字符串("test"),对吗?
3)在实际应用中,用于排序的列可能已被索引,并且不同排序规则在处理实际的非ASCII文本时的索引速度可能会有所不同。 - Halil Özgür这篇帖子描述得非常清楚。
简而言之:utf8_unicode_ci
使用Unicode标准中定义的Unicode排序算法,而utf8_general_ci
则是一种更简单的排序顺序,其结果为“不够准确”的排序结果。
utf8_general_ci
可能适合你。 - Shelvacuutf8_unicode_ci
,假装有缺陷的版本不存在即可。 - tchrist1/3
的正确结果。 - Stijn de Witt正如我们可以在这里读到的Peter Gulutzan所说,排序/比较波兰字母“Ł”(带划线的L- HTML转义:Ł
)(小写字母:“ł”-HTML转义码: ł
)有所不同 - 我们有以下假设:
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';
如果单元格的排序规则为utf8mb4_general_ci
,则会返回该行,但如果与utf8mb4_unicode_ci
排序规则一起排序,则不会返回该行!
另一方面,在utf8mb4_unicode_ci
中,a=ª
和ß=ss
,而在utf8mb4_general_ci
中则不是这样。因此,想象一下你有一行数据:name="ªßi"
,那么
select id from users where name='assi';
如果协同排序规则设置为utf8mb4_unicode_ci
,则会返回该行,但如果协同排序规则设置为utf8mb4_general_ci
,则不会返回该行。
每个协同排序规则的完整匹配列表可以在此处找到。
简言之:
如果您需要更好的排序顺序,请使用utf8_unicode_ci
(这是首选方法),
但如果您非常关注性能,请使用utf8_general_ci
,但要知道它有点过时。
从性能方面来看,差异非常微小。
> select strcmp('が', 'か' collate utf8mb4_unicode_ci); #0
> strcmp('びよういん', 'びょういん' collate utf8mb4_unicode_520_ci); #0
相比之下,一般的操作提供
> select strcmp('が', 'か' collate utf8mb4_general_ci); #1
utf8[mb4]_unicode_ci
,那么你可能更喜欢utf8[mb4]_unicode_520_ci
。 - Rick Jamesutf8mb4_0900_ai_ci
是更好的选择。 - Rick James