it-swarm.dev

Qual é a diferença entre utf8_general_ci e utf8_unicode_ci

Entre utf8_general_ci e utf8_unicode_ci, existem diferenças em termos de desempenho?

924
KahWee Teng

Esses dois agrupamentos são para a codificação de caracteres UTF-8. As diferenças estão em como o texto é classificado e comparado.

Nota: Desde o MySQL 5.5.3 você deve usar utf8mb4 em vez de utf8. Ambos se referem à codificação UTF-8, mas o utf8 mais antigo tinha uma limitação específica do MySQL, impedindo o uso de caracteres numerados acima de 0xFFFD.

  • Precisão

    utf8mb4_unicode_ci é baseado no padrão Unicode para classificação e comparação, que classifica com precisão em uma ampla variedade de idiomas.

    utf8mb4_general_ci falha ao implementar todas as regras de ordenação Unicode, o que resultará em uma ordenação indesejável em algumas situações, como ao usar determinados idiomas ou caracteres.

  • desempenho

    utf8mb4_general_ci é mais rápido nas comparações e na classificação, porque requer muitos atalhos relacionados ao desempenho.

    Nos servidores modernos, esse aumento de desempenho será quase insignificante. Ele foi criado em uma época em que os servidores tinham uma pequena fração do desempenho da CPU dos computadores atuais.

    utf8mb4_unicode_ci, que usa as regras do Unicode para classificação e comparação, emprega um algoritmo bastante complexo para classificação correta em uma ampla gama de idiomas e ao usar uma grande variedade de caracteres especiais. Essas regras precisam levar em conta as convenções específicas do idioma; nem todo mundo classifica seus personagens no que chamaríamos de 'ordem alfabética'.

No que diz respeito às linguagens latinas (ou seja, "européias"), não há muita diferença entre a classificação Unicode e a classificação simplificada utf8mb4_general_ci no MySQL, mas ainda existem algumas diferenças:

  • Por exemplo, o agrupamento Unicode classifica "ß" como "ss" e "Œ" como "OE" como pessoas usando esses caracteres normalmente queriam, enquanto utf8mb4_general_ci os classifica como caracteres únicos (presumivelmente como "s" e "e" respectivamente ).

  • Alguns caracteres Unicode são definidos como ignoráveis, o que significa que eles não devem contar para a ordem de classificação e a comparação deve passar para o próximo caractere. utf8mb4_unicode_ci manipula estes corretamente.

Em idiomas não latinos, como idiomas asiáticos ou idiomas com alfabetos diferentes, pode haver muitas diferenças mais entre a classificação Unicode e a classificação simplificada utf8mb4_general_ci. A adequação de utf8mb4_general_ci dependerá muito do idioma usado. Para alguns idiomas, será bastante inadequado.

O que você deve usar?

Não há praticamente nenhuma razão para usar utf8mb4_general_ci, já que deixamos para trás o ponto em que a velocidade da CPU é baixa o suficiente para que a diferença de desempenho seja importante. Seu banco de dados quase certamente será limitado por outros gargalos do que isso.

A diferença de desempenho só será mensurável em situações extremamente especializadas, e se é você, provavelmente já sabe disso. Se você estiver com uma classificação lenta, em quase todos os casos, haverá um problema com seu plano de índices/consultas. Alterar sua função de agrupamento não deve estar no topo da lista de coisas para solucionar problemas.

No passado, algumas pessoas recomendavam usar utf8mb4_general_ci, exceto quando a classificação precisa seria importante o suficiente para justificar o custo de desempenho. Hoje, esse custo de desempenho praticamente desapareceu, e os desenvolvedores estão tratando a internacionalização mais a sério.

Uma outra coisa que acrescentarei é que, mesmo que você saiba que seu aplicativo suporta apenas o idioma inglês, talvez ainda precise lidar com nomes de pessoas, que geralmente contêm caracteres usados ​​em outros idiomas nos quais é tão importante classificar corretamente . Usar as regras do Unicode para tudo ajuda a aumentar a tranquilidade de que as pessoas muito inteligentes do Unicode trabalharam muito para tornar a classificação adequada.

1417
thomasrutter

Eu queria saber qual é a diferença de desempenho entre usar utf8_general_ci e utf8_unicode_ci, mas não encontrei nenhum benchmark listado na internet, então decidi criar benchmarks eu mesmo.

Eu criei uma tabela muito simples com 500.000 linhas:

CREATE TABLE test(
  ID INT(11) DEFAULT NULL,
  Description VARCHAR(20) DEFAULT NULL
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;

Então eu preenchi com dados aleatórios, executando este procedimento armazenado:

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

Em seguida, criei os procedimentos armazenados a seguir para fazer um benchmark de SELECT simples, SELECT com LIKE e classificação (SELECT com 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;

Nos procedimentos armazenados acima utf8_general_ci collation é usado, mas é claro que durante os testes eu usei utf8_general_ci e utf8_unicode_ci.

Eu chamei cada procedimento armazenado 5 vezes para cada agrupamento (5 vezes para utf8_general_ci e 5 vezes para utf8_unicode_ci) e, em seguida, calculei os valores médios.

Meus resultados são:

benchmark_simple_select()

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

Neste benchmark usando utf8_unicode_ci é mais lento que utf8_general_ci por 3,2%.

benchmark_select_like()

  • com utf8_general_ci: 11,441 ms
  • com utf8_unicode_ci: 12,811 ms

Neste benchmark usando utf8_unicode_ci é mais lento que utf8_general_ci em 12%.

benchmark_order_by()

  • com utf8_general_ci: 11,944 ms
  • com utf8_unicode_ci: 12,887 ms

Neste benchmark usando utf8_unicode_ci é mais lento que utf8_general_ci por 7,9%.

145
nightcoder

Este post descreve muito bem.

Em suma: utf8_unicode_ci usa o algoritmo de agrupamento Unicode, conforme definido nos padrões Unicode, enquanto utf8_general_ci é uma ordem de classificação mais simples que resulta em resultados de classificação "menos precisos".

36
Michael Madsen

Veja o manual do mysql, Conjuntos de Caracteres Unicode seção:

Para qualquer conjunto de caracteres Unicode, as operações executadas usando o agrupamento _general_ci são mais rápidas que as do agrupamento _unicode_ci. Por exemplo, as comparações para o agrupamento utf8_general_ci são mais rápidas, mas um pouco menos corretas, do que as comparações para utf8_unicode_ci. A razão para isto é que o utf8_unicode_ci suporta mapeamentos como expansões; isto é, quando um caractere se compara como igual a combinações de outros caracteres. Por exemplo, em alemão e algumas outras línguas, “ß” é igual a “ss”. utf8_unicode_ci também suporta contrações e caracteres ignoráveis. utf8_general_ci é um agrupamento herdado que não suporta expansões, contrações ou caracteres ignoráveis. Pode fazer apenas comparações um-para-um entre os caracteres.

Então, para resumir, utf_general_ci usa um conjunto de comparações menor e menos correto (de acordo com o padrão) do que utf_unicode_ci que deve implementa todo o padrão. O conjunto general_ci será mais rápido porque há menos computação para fazer.

6
Dana the Sane

Em poucas palavras:

Se você precisar de uma melhor ordem de classificação - use utf8_unicode_ci (este é o método preferido),

mas se você está totalmente interessado em performance - use utf8_general_ci, mas saiba que está um pouco desatualizado.

As diferenças em termos de desempenho são muito pequenas.

6
simhumileco

Alguns detalhes (PL)

Como podemos ler aqui ( Peter Gulutzan ) há diferença na classificação/comparação polonês letra "Ł" (L com acidente vascular cerebral - html esc: Ł) (minúscula: "ł" - html esc: ł) - temos a seguinte suposição:

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

Em polonês, a letra do idioma Ł é depois da letra L e antes de M. Nenhuma dessas codificações é melhor ou pior - depende das suas necessidades.

2
Kamil Kiełczewski