Existe uma referência de desempenho do MySQL para medir o impacto de utf8_unicode_ci versus utf8_general_ci?

13

Li aqui e ali que o uso do utf8_unicode_ciagrupamento garante um melhor tratamento do texto unicode (por exemplo, ele sabe como expandir caracteres como 'œ' para 'oe' para pesquisa e pedido) em comparação com o padrão, utf8_general_cique basicamente retira os diacríticos. Infelizmente, ambas as fontes indicam que utf8_unicode_cié um pouco mais lento que utf8_general_ci.

Então, minha pergunta é: o que significa "um pouco mais lento"? Alguém já executou benchmarks? Estamos falando de um impacto no desempenho de -0,01% ou algo como -25%?

Obrigado pela ajuda.

MiniQuark
fonte
Quanto a uma referência, por que não usar o tempo de consulta? Posso ser um idiota, mas e se você executasse uma VM e testasse o tempo de consulta em uma consulta complicada grande para as duas codificações de caracteres? (Eu não vi benchmarking feito antes)
Ablue

Respostas:

8

Bem, eu não encontrei nenhum benchmark na Internet, então decidi fazer benchmarks sozinho.

Criei uma tabela muito simples com 500000 linhas:

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

Em seguida, preenchi-o 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 seguintes procedimentos armazenados para fazer o benchmark simples SELECT, SELECT com LIKE e classificação (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 procedimentos armazenados acima, o agrupamento utf8_general_ci é usado, mas é claro que durante os testes eu usei utf8_general_ci e utf8_unicode_ci.

Chamei cada procedimento armazenado 5 vezes para cada agrupamento (5 vezes para utf8_general_ci e 5 vezes para utf8_unicode_ci) e calculei os valores médios.

Aqui estão os resultados:

benchmark_simple_select () com utf8_general_ci: 9957 ms
benchmark_simple_select () com utf8_unicode_ci: 10271 ms
Neste benchmark, o uso de utf8_unicode_ci é mais lento que utf8_general_ci em 3,2%.

benchmark_select_like () com utf8_general_ci: 11441 ms
benchmark_select_like () com utf8_unicode_ci: 12811 ms
Neste benchmark, o uso de 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
Nesse benchmark, o uso de utf8_unicode_ci é mais lento que o utf8_general_ci em 7,9%.

nightcoder
fonte
2

Não vi nenhum benchmark, mas você pode executar o seu próprio usando a função BENCHMARK :

BENCHMARK (contagem, expr)

Conforme recomendado por Matthew, você pode executar uma instalação paralela do MYSQL, mas considere que pode haver uma grande diferença entre diferentes arquiteturas (sparc, intel, 32bit, 64bit, ...).

tmow
fonte