在utf8_general_ci和utf8_unicode_ci之间,在性能方面有什么不同吗?


当前回答

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

在MariaDB中,utf8mb4_ja_0900_as_cs不可用,因此必须使用unicode或通用选项之一。然而,unicode对待浊音和浊音等是一样的。例如,びよういん(美容师)被视为等同于びょういん(医院)。这显然是不正确的行为。

> select strcmp('が', 'か' collate utf8mb4_unicode_ci); #0
> strcmp('びよういん', 'びょういん' collate utf8mb4_unicode_520_ci); #0 

而将军给出

> select strcmp('が', 'か' collate utf8mb4_general_ci); #1

换句话说,unicode对浊音假名和浊音假名一视同仁。在我看来,这并不可取。

编辑:使用uca1400_ai_cs可能更好,它在MariaDB的新版本中可用,并使上述排序正确。

其他回答

这篇文章描述得很好。

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

我想知道使用utf8_general_ci和utf8_unicode_ci之间的性能差异是什么,但我没有在互联网上找到任何基准测试,所以我决定自己创建基准测试。

我创建了一个非常简单的50万行表:

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 with LIKE和排序(SELECT with 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次(utf8_general_ci调用5次,utf8_unicode_ci调用5次),然后计算平均值。

我的结果是:

benchmark_simple_select ()

utf8_general_ci: 9,957 ms utf8_unicode_ci: 10,271 ms

在这个基准测试中,使用utf8_unicode_ci比使用utf8_general_ci慢3.2%。

benchmark_select_like ()

使用utf8_general_ci: 11,441 ms 使用utf8_unicode_ci: 12,811 ms

在这个基准测试中,使用utf8_unicode_ci比使用utf8_general_ci慢12%。

benchmark_order_by ()

使用utf8_general_ci: 11,944 ms 使用utf8_unicode_ci: 12,887 ms

在这个基准测试中,使用utf8_unicode_ci比使用utf8_general_ci慢7.9%。

简单来说:

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

但是如果您对性能非常感兴趣,可以使用utf8_general_ci,但要知道它有点过时了。

性能方面的差异非常微小。

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

在MariaDB中,utf8mb4_ja_0900_as_cs不可用,因此必须使用unicode或通用选项之一。然而,unicode对待浊音和浊音等是一样的。例如,びよういん(美容师)被视为等同于びょういん(医院)。这显然是不正确的行为。

> select strcmp('が', 'か' collate utf8mb4_unicode_ci); #0
> strcmp('びよういん', 'びょういん' collate utf8mb4_unicode_520_ci); #0 

而将军给出

> select strcmp('が', 'か' collate utf8mb4_general_ci); #1

换句话说,unicode对浊音假名和浊音假名一视同仁。在我看来,这并不可取。

编辑:使用uca1400_ai_cs可能更好,它在MariaDB的新版本中可用,并使上述排序正确。

一些细节(PL)

正如我们可以在这里(Peter Gulutzan)读到的,排序/比较波兰字母“Ł”(L与笔画- html esc: Ł)(小写:“ova”- 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之前,没有哪个编码更好或更差——这取决于你的需要。