¿Cuál es la diferencia entre utf8_general_ci y utf8_unicode_ci?
Entre utf8_general_ci
y utf8_unicode_ci
, ¿hay diferencias en cuanto a rendimiento?
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_ci
y _general_ci
son 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_ci
reglas equivalentes basadas en Unicode 5.2, o MySQL 8.x específico _0900_ai_ci
para reglas equivalentes basadas en Unicode 9.0 (y sin _general_ci
variante equivalente). Las personas que lean esto ahora probablemente deberían usar una de estas intercalaciones más nuevas en lugar de _unicode_ci
o _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 utf8mb4
en lugar de utf8
para 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_ci
se 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_ci
es 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_ci
má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_ci
clasificació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_ci
clasifica 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_ci
los 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_ci
clasificación simplificada. 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 utf8mb4_general_ci
ya 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_ci
excepto 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_ci
es 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, ci
sirve 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, unicode
o general
se 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 unicode
hay general
dos 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 unicode
utiliza reglas de Unicode 4.0. Las versiones recientes de MySQL y MariaDB agregan los conjuntos de reglas unicode_520
usando reglas de Unicode 5.2, y MySQL 8.x agrega 0900
(eliminando la parte "unicode_") usando reglas de Unicode 9.0.
Y por último, utf8mb4
está, por supuesto, la codificación de caracteres utilizada internamente. En esta respuesta estoy hablando sólo de codificaciones basadas en Unicode.
Quería saber cuál es la diferencia de rendimiento entre usar utf8_general_ci
y 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
, SELECT
with LIKE
y sorting ( SELECT
with 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_ci
se usa la intercalación, pero, por supuesto, durante las pruebas usé ambos utf8_general_ci
y utf8_unicode_ci
.
Llamé a cada procedimiento almacenado 5 veces para cada clasificació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
: 9,957 ms - con
utf8_unicode_ci
: 10,271 ms
En este punto de referencia el uso utf8_unicode_ci
es inferior utf8_general_ci
al 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_ci
es inferior utf8_general_ci
al 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_ci
es inferior utf8_general_ci
al 7,9%.