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?

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 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 sorting 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 ordenação indesejável em algumas situações, como ao usar linguagens ou caracteres específicos.

  • atuação

    utf8mb4_general_ci é mais rápido nas comparações e na sorting, porque requer utf8mb4_general_ci 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 sorting e comparação, emprega um algoritmo bastante complexo para ordenaçã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 sorting Unicode e a sorting 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 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 sorting e a comparação deve passar para o próximo caractere. utf8mb4_unicode_ci lida com isso corretamente.

Em idiomas não latinos, como idiomas asiáticos ou idiomas com alfabetos diferentes, pode haver muito mais diferenças entre a sorting Unicode e a sorting simplificada utf8mb4_general_ci . A adequação do utf8mb4_general_ci dependerá fortemente da linguagem utilizada. Para alguns idiomas, será bastante inadequado.

O que você deve usar?

Não há praticamente nenhuma razão para usar o 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 database 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ê tiver uma sorting lenta, em quase todos os casos, haverá um problema com seu plano de índices / consulta. Alterar sua function de agrupamento não deve estar no topo da lista de coisas para solucionar problemas.

No passado, algumas pessoas recomendavam usar o utf8mb4_general_ci exceto quando a sorting precisa fosse 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 sorting adequada.

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 randoms, 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 seguintes stored procedures para o benchmark SELECT simples, SELECT com LIKE e sorting (SELECT com ORDER BY):

 CREATE 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 stored procedures acima utf8_general_ci, o agrupamento é usado, mas é claro que durante os testes eu usei tanto o utf8_general_ci quanto o 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: 9957 ms
benchmark_simple_select () com utf8_unicode_ci: 10271 ms
Neste benchmark usando utf8_unicode_ci é mais lento que utf8_general_ci por 3,2%.

benchmark_select_like () com utf8_general_ci: 11441 ms
benchmark_select_like () com utf8_unicode_ci: 12811 ms
Neste benchmark usando utf8_unicode_ci é mais lento que utf8_general_ci em 12%.

benchmark_order_by () com utf8_general_ci: 11944 ms
benchmark_order_by () com utf8_unicode_ci: 12887 ms
Neste benchmark usando utf8_unicode_ci é mais lento que utf8_general_ci por 7,9%.

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 sorting mais simples que resulta em resultados de sorting “menos precisos”.

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

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 é comparado 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 de 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 implementar o padrão inteiro. O conjunto general_ci será mais rápido porque há menos computação para fazer.

Em poucas palavras:

Se você precisa de uma melhor ordem de sorting – use utf8_unicode_ci (este é o método preferido),

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

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