Cuál es la diferencia entre utf8_general_ci y utf8_unicode_ci

Entre utf8_general_ci y utf8_unicode_ci , ¿hay alguna diferencia en términos de rendimiento?

Estas dos intercalaciones son ambas para la encoding de caracteres UTF-8. Las diferencias están en cómo se clasifica y se compara el texto.

Nota: desde MySQL 5.5.3 debe usar utf8mb4 lugar de utf8 . Ambos se refieren a la encoding UTF-8, pero el utf8 anterior tenía una limitación específica de MySQL que impedía el uso de caracteres numerados por encima de 0xFFFD.

  • Exactitud

    utf8mb4_unicode_ci se basa en el estándar Unicode para clasificación y comparación, que ordena con precisión en una amplia gama de idiomas.

    utf8mb4_general_ci no puede implementar todas las reglas de ordenamiento Unicode, lo que dará como resultado una clasificación no deseada en algunas situaciones, como cuando se utilizan determinados idiomas o caracteres.

  • Actuación

    utf8mb4_general_ci es más rápido en las comparaciones y la ordenación, ya que requiere una serie de atajos relacionados con el rendimiento.

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

    utf8mb4_unicode_ci , que utiliza las reglas Unicode para ordenar y comparar, emplea un algoritmo bastante complejo para una clasificación correcta en una amplia gama de idiomas y al utilizar una amplia gama de caracteres especiales. Estas reglas deben tener en cuenta las convenciones específicas del idioma; no todos clasifican a sus personajes 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 ordenación Unicode y la ordenación simplificada utf8mb4_general_ci en MySQL, pero todavía hay algunas diferencias:

  • Por ejemplo, la intercalación Unicode clasifica “ß” como “ss”, y “Œ” como “OE”, como las personas que utilizan esos caracteres normalmente querrían, mientras que utf8mb4_general_ci clasifica como caracteres individuales (presumiblemente como “s” y “e” respectivamente )

  • Algunos caracteres Unicode se definen como ignorables, lo que significa que no deben tenerse en cuenta para el orden de clasificación y la comparación debe pasar al siguiente carácter. utf8mb4_unicode_ci maneja estos correctamente.

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

¿Qué deberías usar?

Es casi seguro que no hay razón para usar utf8mb4_general_ci , ya que hemos dejado atrás el punto donde la velocidad de la CPU es lo suficientemente baja para que la diferencia de rendimiento sea importante. Su base de datos casi seguramente estará limitada por otros cuellos de botella que esto.

La diferencia en el rendimiento solo se podrá medir en situaciones extremadamente especializadas, y si ese es usted, probablemente ya lo sepa. Si experimenta una clasificación lenta, en casi todos los casos será un problema con sus índices / plan de consulta. Cambiar la función de intercalación no debe ser alta en la lista de cosas para solucionar problemas.

En el pasado, algunas personas recomendaban usar utf8mb4_general_ci excepto cuando una clasificación precisa iba a ser lo suficientemente importante como para justificar el costo de rendimiento. Hoy, ese costo de rendimiento casi ha desaparecido, y los desarrolladores están tratando la internacionalización más en serio.

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

Quería saber cuál es la diferencia de rendimiento entre el uso de utf8_general_ci y utf8_unicode_ci, pero no encontré ninguna referencia listada en Internet, así que decidí crear puntos de referencia yo mismo.

Creé una tabla muy simple con 500000 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 los parámetros SELECT, SELECT con LIKE y Sorting (SELECT con 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 

En los procedimientos almacenados anteriores se usa la intercalación utf8_general_ci, pero por supuesto durante las pruebas utilicé utf8_general_ci y utf8_unicode_ci.

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

Mis resultados son:

benchmark_simple_select () con utf8_general_ci: 9957 ms
benchmark_simple_select () con utf8_unicode_ci: 10271 ms
En este punto de referencia, el uso de utf8_unicode_ci es más lento que utf8_general_ci en un 3,2%.

benchmark_select_like () con utf8_general_ci: 11441 ms
benchmark_select_like () con utf8_unicode_ci: 12811 ms
En este punto de referencia el uso de utf8_unicode_ci es más lento que utf8_general_ci en un 12%.

benchmark_order_by () con utf8_general_ci: 11944 ms
benchmark_order_by () con utf8_unicode_ci: 12887 ms
En este punto de referencia el uso de utf8_unicode_ci es más lento que utf8_general_ci en 7.9%.

Esta publicación lo describe muy bien.

En resumen: utf8_unicode_ci usa el Algoritmo de intercalación Unicode como se define en los estándares Unicode, mientras que utf8_general_ci es un orden de clasificación más simple que da como resultado resultados de clasificación “menos precisos”.

Consulte el manual de mysql, sección Conjuntos de caracteres Unicode :

Para cualquier conjunto de caracteres Unicode, las operaciones realizadas usando la intercalación _general_ci son más rápidas que las de la intercalación _unicode_ci. Por ejemplo, las comparaciones para la intercalación utf8_general_ci son más rápidas, pero ligeramente menos correctas, que las comparaciones para utf8_unicode_ci. La razón de esto es que utf8_unicode_ci admite asignaciones tales como expansiones; es decir, cuando un personaje se compara como igual a las combinaciones de otros personajes. Por ejemplo, en alemán y en otros idiomas, “ß” es igual a “ss”. utf8_unicode_ci también admite contracciones y caracteres ignorables. utf8_general_ci es una clasificación heredada que no admite expansiones, contracciones o caracteres ignorables. Solo puede hacer comparaciones uno a uno entre los personajes.

Para resumir, utf_general_ci usa un conjunto de comparaciones más pequeño y menos correcto (de acuerdo con el estándar) que utf_unicode_ci, que debería implementar todo el estándar. El conjunto general_ci será más rápido porque hay menos cálculos que hacer.

En palabras breves:

Si necesita ordenar mejor, use utf8_unicode_ci (este es el método preferido),

pero si está completamente interesado en el rendimiento, use utf8_general_ci , pero sepa que está un poco desactualizado.

Las diferencias en términos de rendimiento son muy leves.