Entre utf8_general_ci
y utf8_unicode_ci
, ¿hay alguna diferencia en términos de rendimiento?
utf8[mb4]_unicode_ci
, puede que le guste utf8[mb4]_unicode_520_ci
aún más.
utf8mb4_0900_ai_ci
.
Entre utf8_general_ci
y utf8_unicode_ci
, ¿hay alguna diferencia en términos de rendimiento?
utf8[mb4]_unicode_ci
, puede que le guste utf8[mb4]_unicode_520_ci
aún más.
utf8mb4_0900_ai_ci
.
Respuestas:
Estas dos intercalaciones son para la codificación de caracteres UTF-8. Las diferencias están en cómo se clasifica y compara el texto.
Nota: En MySQL debe usar en utf8mb4
lugar de utf8
. Confusamente, utf8
es una implementación UTF-8 defectuosa de las primeras versiones de MySQL que solo queda por compatibilidad con versiones anteriores. La versión fija recibió el nombre utf8mb4
.
Nota: Las versiones más recientes de MySQL han actualizado las reglas de clasificación de Unicode, disponibles con nombres como utf8mb4_0900_ai_ci
reglas equivalentes basadas en Unicode 9.0, y sin una _general
variante equivalente . Las personas que lean esto ahora probablemente deberían usar una de estas colaciones más nuevas en lugar de cualquiera _unicode
o _general
. Gran parte de lo que está escrito a continuación ya no es de gran interés si puedes usar una de las colaciones más nuevas.
Diferencias clave
utf8mb4_unicode_ci
se basa en las reglas oficiales de Unicode para la clasificación y comparación universales, que se clasifican 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 tan bien como sea posible mientras toma muchos atajos diseñados para mejorar la velocidad. No sigue las reglas de Unicode y resultará en una clasificación o comparación indeseable en algunas situaciones, como cuando se usan idiomas o caracteres particulares.
En los servidores modernos, este aumento de rendimiento será casi insignificante. Fue ideado en un momento en que los servidores tenían una pequeña fracción del rendimiento de la CPU de las computadoras de hoy.
Beneficios de utf8mb4_unicode_ci
más deutf8mb4_general_ci
utf8mb4_unicode_ci
, que utiliza las reglas Unicode para la clasificación y la comparación, emplea un algoritmo bastante complejo para la clasificación correcta 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 todos clasifican 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 utf8mb4_general_ci
ordenación simplificada en MySQL, pero aún existen algunas diferencias:
Por ejemplo, la intercalación Unicode ordena "ß" como "ss" y "Œ" como "OE" como lo desearían normalmente 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
maneja estos adecuadamente.
En los idiomas no latinos, como los idiomas asiáticos o los idiomas con diferentes alfabetos, puede haber muchas más diferencias entre la ordenación Unicode y la utf8mb4_general_ci
ordenación simplificada . La idoneidad de utf8mb4_general_ci
dependerá en gran medida del lenguaje utilizado. Para algunos idiomas, será bastante inadecuado.
¿Qué deberías usar?
Es casi seguro que ya 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 como para que la diferencia de rendimiento sea importante. Es casi seguro que su base de datos estará limitada por otros cuellos de botella además de este.
En el pasado, algunas personas recomendaban usar, utf8mb4_general_ci
excepto cuando la clasificación precisa sería 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 con más seriedad.
Hay que argumentar que si la velocidad es más importante para usted que la precisión, es mejor que no haga ningún tipo de clasificación. Es trivial hacer un algoritmo más rápido si no necesita 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 sabe que su 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 ordenarlos correctamente . El uso de las reglas de 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.
Que significan las partes
En primer lugar, ci
es para la clasificación y comparación sin distinción entre mayúsculas y minúsculas . Esto significa que es adecuado para datos textuales, y el caso no es importante. Los otros tipos de cotejo son cs
( distingue entre mayúsculas y minúsculas) para datos textuales donde el caso es importante y bin
, para donde la codificación debe coincidir, bit por bit, que es adecuado para campos que realmente son datos binarios codificados (incluyendo, por ejemplo, Base64). La clasificación sensible a mayúsculas y minúsculas conduce a algunos resultados extraños y la comparación sensible a mayúsculas y minúsculas puede dar lugar a valores duplicados que difieren solo en mayúsculas y minúsculas, por lo que las clasificaciones sensibles a mayúsculas y minúsculas caen en desuso para los datos textuales; si el caso es significativo para usted, entonces la puntuación es ignorable etc., probablemente también sea significativo, y una intercalación binaria podría ser más apropiada.
A continuación, unicode
o se general
refiere a las reglas específicas de clasificación y comparación, en particular, la forma en que el texto se normaliza o compara. Hay muchos conjuntos diferentes de reglas para la codificación de caracteres utf8mb4, unicode
y general
son 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
usa reglas de Unicode 4.0. Las versiones recientes de MySQL agregan los conjuntos de unicode_520
reglas usando reglas de Unicode 5.2 y 0900
(descartando la parte "unicode_") usando reglas de Unicode 9.0.
Y, por último, utf8mb4
es la codificación de caracteres utilizada internamente. En esta respuesta, solo estoy hablando de codificaciones basadas en Unicode.
utf8_general_ci
: simplemente no funciona. Es un retroceso a los viejos tiempos malos de la abstinencia ASCII de hace cincuenta años. La coincidencia sin distinción entre mayúsculas y minúsculas Unicode no se puede realizar sin el mapa de mayúsculas y minúsculas del UCD. Por ejemplo, "Σίσυφος" tiene tres sigmas diferentes en él; o cómo la minúscula de "TSCHüẞ" es "tschüβ", pero la mayúscula de "tschüβ" es "TSCHÜSS". Puedes tener razón o puedes ser rápido. Por lo tanto, debe usar utf8_unicode_ci
, porque si no le importa la corrección, entonces es trivial hacerlo infinitamente rápido.
"か" == "が"
o "ǽ" == "æ"
. Para ordenar esto tiene sentido, pero podría ser sorprendente al seleccionar a través de igualdades o lidiar con índices únicos - bugs.mysql.com/bug.php?id=16526
utf8mb4
es la única opción correcta . Contigo utf8
está atascado en alguna variante de 3 bytes de UTF8 solo de MySQL que solo MySQL (y MariaDB) saben qué hacer. El resto del mundo está utilizando UTF8, que puede contener hasta 4 bytes por carácter . Los desarrolladores de MySQL nombraron erróneamente su codificación homebrew utf8
y para no romper la compatibilidad con versiones anteriores, ahora deben referirse al UTF8 real como utf8mb4
.
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í crearlo.
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 de manera simple SELECT
, SELECT
con LIKE
y ordenar ( SELECT
con 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 utf8_general_ci
se utiliza la clasificación anterior , pero, por supuesto, durante las pruebas utilicé ambos 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()
utf8_general_ci
: 9,957 ms utf8_unicode_ci
: 10,271 ms En este punto de referencia, el uso utf8_unicode_ci
es más lento que utf8_general_ci
en un 3,2%.
benchmark_select_like()
utf8_general_ci
: 11,441 ms utf8_unicode_ci
: 12,811 ms En este punto de referencia, el uso utf8_unicode_ci
es más lento que utf8_general_ci
en un 12%.
benchmark_order_by()
utf8_general_ci
: 11,944 ms utf8_unicode_ci
: 12,887 ms En este punto de referencia, el uso utf8_unicode_ci
es más lento que utf8_general_ci
en un 7,9%.
utf8_general_ci
es demasiado mínima para que valga la pena usarla.
CONV(FLOOR(RAND() * 99999999999999), 20, 36)
solo genera ASCII, y ningún carácter Unicode para ser procesado por los algoritmos de las intercalaciones. 2) Description = 'test' COLLATE ...
y Description LIKE 'test%' COLLATE ...
solo procesan una sola cadena ("prueba") en tiempo de ejecución, ¿no? 3) En aplicaciones reales, las columnas utilizadas en la ordenación probablemente se indexarían, y la velocidad de indexación en diferentes intercalaciones con texto real no ASCII podría diferir.
Esta publicación lo describe muy bien.
En resumen: utf8_unicode_ci usa el Algoritmo de clasificació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 resulta en resultados de clasificación "menos precisos".
utf8_unicode_ci
y finge que el otro no existe.
utf8_general_ci
puede ser para ti
Consulte el manual de mysql, sección Juegos de caracteres Unicode :
Para cualquier conjunto de caracteres Unicode, las operaciones realizadas con la clasificación _general_ci son más rápidas que las de la clasificación _unicode_ci. Por ejemplo, las comparaciones para la colación utf8_general_ci son más rápidas, pero un poco menos correctas, que las comparaciones para utf8_unicode_ci. La razón de esto es que utf8_unicode_ci admite mapeos como expansiones; es decir, cuando un personaje se compara como igual a combinaciones de otros personajes. Por ejemplo, en alemán y otros idiomas, "ß" es igual a "ss". utf8_unicode_ci también admite contracciones y caracteres ignorables. utf8_general_ci es una recopilació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 utiliza un conjunto de comparaciones más pequeño y menos correcto (según 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.
utf8_unicode_ci
y finge que la versión defectuosa no existe.
0
y 1
, no un bool. :) Por ejemplo, seleccionar puntos geográficos en un cuadro delimitador es una aproximación de 'puntos cercanos' que no es tan bueno como calcular la distancia entre el punto y el punto de referencia y filtrar en eso. Pero ambos son una aproximación y, de hecho, la corrección completa no es posible en su mayoría. Vea la paradoja de la costa y el IEEE 754
1/3
En pocas palabras:
Si necesita un mejor orden de clasificación, use utf8_unicode_ci
(este es el método preferido),
pero si está completamente interesado en el rendimiento, úselo utf8_general_ci
, pero sepa que está un poco desactualizado.
Las diferencias en términos de rendimiento son muy leves.
Como podemos leer aquí ( Peter Gulutzan ) hay una diferencia en la clasificación / comparación de la letra polaca "Ł" (L con trazo - html esc:) Ł
(minúscula: "ł" - html esc:) ł
- tenemos la siguiente suposición:
utf8_polish_ci Ł greater than L and less than M
utf8_unicode_ci Ł greater than L and less than M
utf8_unicode_520_ci Ł equal to L
utf8_general_ci Ł greater than Z
En idioma polaco, la letra Ł
es después de la letra L
y antes M
. Ninguno de estos códigos es mejor o peor, depende de sus necesidades.
Hay dos grandes diferencias en la clasificación y la coincidencia de caracteres:
Clasificación :
utf8mb4_general_ci
elimina todos los acentos y los ordena uno por uno, lo que puede crear resultados de clasificación incorrectos.utf8mb4_unicode_ci
tipo exacto.Coincidencia de personajes
Coinciden con los personajes de manera diferente.
Por ejemplo, en utf8mb4_unicode_ci
usted tiene i != ı
, pero en utf8mb4_general_ci
él tieneı=i
.
Por ejemplo, imagina que tienes una fila con name="Yılmaz"
. Entonces
select id from users where name='Yilmaz';
devolvería la fila si la colocación es utf8mb4_general_ci
, pero si está colocada con utf8mb4_unicode_ci
ella no lo haría devolvería la fila!
Por otro lado tenemos eso a=ª
y ß=ss
en lo utf8mb4_unicode_ci
que no es el caso utf8mb4_general_ci
. Entonces imagina que tienes una pelea con name="ªßi"
, entonces
select id from users where name='assi';
devolvería la fila si la colocación es utf8mb4_unicode_ci
, pero no devolvería una fila si la colocación se establece enutf8mb4_general_ci
.
Puede encontrar una lista completa de coincidencias para cada colocación aquí .
Según esta publicación, hay un beneficio de rendimiento considerablemente grande en MySQL 5.7 cuando se usa utf8mb4_general_ci en lugar de utf8mb4_unicode_ci: https://www.percona.com/blog/2019/02/27/charset-and-collation-settings-impact -on-mysql-performance /