¿Cuál es la diferencia entre utf8_general_ci y utf8_unicode_ci?

Resuelto KahWee Teng asked hace 15 años • 9 respuestas

Entre utf8_general_ciy utf8_unicode_ci, ¿hay diferencias en cuanto a rendimiento?

KahWee Teng avatar Apr 20 '09 10:04 KahWee Teng
Aceptado

Para aquellas personas que aún llegan a esta pregunta en 2020 o después, existen opciones más nuevas que pueden ser mejores que ambas . Por ejemplo, utf8_unicode_520_ci.

Todas estas intercalaciones son para la codificación de caracteres UTF-8. Las diferencias están en cómo se ordena y compara el texto.

_unicode_ciy _general_cison dos conjuntos diferentes de reglas para ordenar y comparar texto según la forma que esperamos. Las versiones más recientes de MySQL también introducen nuevos conjuntos de reglas, como _unicode_520_cireglas equivalentes basadas en Unicode 5.2, o MySQL 8.x específico _0900_ai_cipara reglas equivalentes basadas en Unicode 9.0 (y sin _general_civariante equivalente). Las personas que lean esto ahora probablemente deberían usar una de estas intercalaciones más nuevas en lugar de _unicode_cio _general_ci. La descripción de esas colaciones más antiguas a continuación se proporciona únicamente por interés.

MySQL actualmente está abandonando una implementación UTF-8 antigua y defectuosa. Por ahora, debes usar utf8mb4en lugar de utf8para la parte de codificación de caracteres, para asegurarte de obtener la versión corregida. La versión defectuosa permanece por compatibilidad con versiones anteriores, aunque está en desuso.

Diferencias clave

  • utf8mb4_unicode_cise basa en las reglas oficiales Unicode para clasificación y comparación universal, que clasifica con precisión en una amplia gama de idiomas.

  • utf8mb4_general_cies un conjunto simplificado de reglas de clasificación que tiene como objetivo hacerlo lo mejor posible mientras toma muchos atajos diseñados para mejorar la velocidad. No sigue las reglas de Unicode y dará como resultado una clasificación o comparación no deseada en algunas situaciones, como cuando se utilizan idiomas o caracteres particulares.

    En los servidores modernos, este aumento de rendimiento será prácticamente insignificante. Fue ideado en una época en la que los servidores tenían una pequeña fracción del rendimiento de la CPU de las computadoras actuales.

Beneficios de utf8mb4_unicode_cimásutf8mb4_general_ci

utf8mb4_unicode_ci, que utiliza las reglas Unicode para ordenar y comparar, emplea un algoritmo bastante complejo para ordenar correctamente en una amplia gama de idiomas y cuando se utiliza una amplia gama de caracteres especiales. Estas reglas deben tener en cuenta las convenciones específicas del idioma; No todo el mundo clasifica sus caracteres en lo que llamaríamos "orden alfabético".

En lo que respecta a los idiomas latinos (es decir, "europeos"), no hay mucha diferencia entre la clasificación Unicode y la utf8mb4_general_ciclasificación simplificada en MySQL, pero todavía hay algunas diferencias:

  • Por ejemplo, la intercalación Unicode ordena "ß" como "ss" y "Œ" como "OE" como normalmente querrían las personas que usan esos caracteres, mientras que los utf8mb4_general_ciclasifica como caracteres individuales (presumiblemente como "s" y "e" respectivamente). .

  • Algunos caracteres Unicode se definen como ignorables, lo que significa que no deberían contar para el orden de clasificación y la comparación debería pasar al siguiente carácter. utf8mb4_unicode_cilos maneja adecuadamente.

En idiomas no latinos, como idiomas asiáticos o idiomas con diferentes alfabetos, puede haber muchas más diferencias entre la clasificación Unicode y la utf8mb4_general_ciclasificación simplificada. La idoneidad de utf8mb4_general_cidependerá en gran medida del idioma utilizado. Para algunos idiomas, será bastante inadecuado.

¿Qué deberías usar?

Es casi seguro que utf8mb4_general_ciya no hay razón para usarlo, ya que hemos dejado atrás el punto en el que la velocidad de la CPU es lo suficientemente baja como para que la diferencia de rendimiento sea importante. Es casi seguro que su base de datos estará limitada por otros obstáculos además de este.

En el pasado, algunas personas recomendaban su uso utf8mb4_general_ciexcepto cuando la clasificación precisa fuera lo suficientemente importante como para justificar el costo de rendimiento. Hoy en día, ese costo de rendimiento prácticamente ha desaparecido y los desarrolladores están tomando la internacionalización más en serio.

Se puede argumentar que si la velocidad es más importante para usted que la precisión, es mejor no realizar ninguna clasificación. Es trivial hacer que un algoritmo sea más rápido si no es necesario que sea preciso. Por lo tanto, utf8mb4_general_cies un compromiso que probablemente no sea necesario por razones de velocidad y probablemente tampoco sea adecuado por razones de precisión.

Otra cosa que agregaré es que incluso si sabes que tu aplicación solo admite el idioma inglés, es posible que de todos modos necesite manejar los nombres de las personas, que a menudo pueden contener caracteres utilizados en otros idiomas en los que es igual de importante ordenarlos correctamente. . El uso de las reglas Unicode para todo ayuda a tener la tranquilidad de saber que las personas muy inteligentes de Unicode han trabajado muy duro para que la clasificación funcione correctamente.

¿Qué significan las partes?

En primer lugar, cisirve para clasificar y comparar sin distinguir entre mayúsculas y minúsculas . Esto significa que es adecuado para datos textuales y las mayúsculas y minúsculas no son importantes. Los otros tipos de intercalación son cs(distinguen entre mayúsculas y minúsculas) para datos textuales donde las mayúsculas y minúsculas son importantes, y bin, para donde la codificación debe coincidir, bit por bit, lo cual es adecuado para campos que en realidad son datos binarios codificados (incluidos, por ejemplo, Base64). La clasificación que distingue entre mayúsculas y minúsculas conduce a algunos resultados extraños y la comparación que distingue entre mayúsculas y minúsculas puede dar como resultado valores duplicados que difieren solo en mayúsculas y minúsculas, por lo que las intercalaciones que distinguen entre mayúsculas y minúsculas están cayendo en desgracia para los datos textuales; si las mayúsculas y minúsculas son importantes para usted, entonces, de lo contrario, la puntuación se puede ignorar. y así sucesivamente probablemente también sea importante, y una intercalación binaria podría ser más apropiada.

A continuación, unicodeo generalse refiere a las reglas específicas de clasificación y comparación, en particular, la forma en que se normaliza o compara el texto. Hay muchos conjuntos diferentes de reglas para la codificación de caracteres utf8mb4, y unicodehay generaldos que intentan funcionar bien en todos los idiomas posibles en lugar de uno específico. Las diferencias entre estos dos conjuntos de reglas son el tema de esta respuesta. Tenga en cuenta que unicodeutiliza reglas de Unicode 4.0. Las versiones recientes de MySQL y MariaDB agregan los conjuntos de reglas unicode_520usando reglas de Unicode 5.2, y MySQL 8.x agrega 0900(eliminando la parte "unicode_") usando reglas de Unicode 9.0.

Y por último, utf8mb4está, por supuesto, la codificación de caracteres utilizada internamente. En esta respuesta estoy hablando sólo de codificaciones basadas en Unicode.

thomasrutter avatar Apr 20 '2009 05:04 thomasrutter

Quería saber cuál es la diferencia de rendimiento entre usar utf8_general_ciy utf8_unicode_ci, pero no encontré ningún punto de referencia en Internet, así que decidí crear puntos de referencia yo mismo.

Creé una tabla muy simple con 500.000 filas:

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

Luego lo llené con datos aleatorios ejecutando este procedimiento almacenado:

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

Luego creé los siguientes procedimientos almacenados para comparar simple SELECT, SELECTwith LIKEy sorting ( SELECTwith 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;

En los procedimientos almacenados anteriores utf8_general_cise usa la intercalación, pero, por supuesto, durante las pruebas usé ambos utf8_general_ciy utf8_unicode_ci.

Llamé a cada procedimiento almacenado 5 veces para cada clasificación (5 veces para utf8_general_ciy 5 veces para utf8_unicode_ci) y luego calculé los valores promedio.

Mis resultados son:

benchmark_simple_select()

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

En este punto de referencia el uso utf8_unicode_cies inferior utf8_general_cial 3,2%.

benchmark_select_like()

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

En este punto de referencia, el uso utf8_unicode_cies inferior utf8_general_cial 12%.

benchmark_order_by()

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

En este punto de referencia, el uso utf8_unicode_cies inferior utf8_general_cial 7,9%.

nightcoder avatar Mar 02 '2013 02:03 nightcoder