Me pregunto si hay una "mejor" opción para la recopilación en MySQL para un sitio web general donde no está 100% seguro de lo que se ingresará. Entiendo que todas las codificaciones deben ser iguales, como MySQL, Apache, HTML y cualquier cosa dentro de PHP.
En el pasado, configuré PHP para que salga en "UTF-8", pero ¿qué cotejo coincide en MySQL? Estoy pensando que es uno de los caracteres UTF-8 queridos, pero he utilizado utf8_unicode_ci
, utf8_general_ci
y utf8_bin
antes.
Respuestas:
La principal diferencia es la precisión de la clasificación (al comparar caracteres en el idioma) y el rendimiento. El único especial es utf8_bin, que es para comparar caracteres en formato binario.
utf8_general_ci
es algo más rápido queutf8_unicode_ci
, pero menos preciso (para ordenar). La codificación específica del lenguaje utf8 (comoutf8_swedish_ci
) contiene reglas de idioma adicionales que las hacen las más precisas para ordenar esos idiomas. La mayoría de las veces lo usoutf8_unicode_ci
(prefiero la precisión a las pequeñas mejoras de rendimiento), a menos que tenga una buena razón para preferir un idioma específico.Puede leer más sobre conjuntos de caracteres Unicode específicos en el manual de MySQL: http://dev.mysql.com/doc/refman/5.0/en/charset-unicode-sets.html
fuente
utf8_unicode_*
utf8mb4
yutf8mb4_unicode_520_ci
. Estos le dan el resto de los chinos, además de una mejor clasificación.En realidad, probablemente quieras usar
utf8_unicode_ci
outf8_general_ci
.utf8_general_ci
ordena eliminando todos los acentos y clasificándolos como si fueran ASCIIutf8_unicode_ci
utiliza el orden de clasificación Unicode, por lo que se ordena correctamente en más idiomasSin embargo, si solo está usando esto para almacenar texto en inglés, estos no deberían diferir.
fuente
Sea muy, muy consciente de este problema que puede ocurrir al usarlo
utf8_general_ci
.MySQL no distinguirá entre algunos caracteres en las sentencias select, si
utf8_general_ci
se utiliza la intercalación. Esto puede conducir a errores muy desagradables, especialmente, por ejemplo, cuando los nombres de usuario están involucrados. Dependiendo de la implementación que use las tablas de la base de datos, este problema podría permitir a los usuarios malintencionados crear un nombre de usuario que coincida con una cuenta de administrador.Este problema se expone al menos en las primeras versiones 5.x: no estoy seguro de si este comportamiento se modificó más adelante.
No soy un DBA, pero para evitar este problema, siempre uso uno en
utf8-bin
lugar de uno que no distinga entre mayúsculas y minúsculas.El siguiente script describe el problema con un ejemplo.
fuente
'value'
y'valUe'
. El objetivo de una recopilación es que proporciona reglas (entre otras cosas) cuando dos cadenas se consideran iguales entre sí.Es mejor usar el juego de caracteres
utf8mb4
con la intercalaciónutf8mb4_unicode_ci
.El conjunto de caracteres
utf8
, solo admite una pequeña cantidad de puntos de código UTF-8, aproximadamente el 6% de los posibles caracteres.utf8
solo es compatible con el plano multilingüe básico (BMP). Hay otros 16 aviones. Cada plano contiene 65.536 caracteres.utf8mb4
Soporta los 17 planos.MySQL truncará los caracteres UTF-8 de 4 bytes, resultando en datos corruptos.
El
utf8mb4
conjunto de caracteres se introdujo en MySQL 5.5.3 el 2010-03-24.Algunos de los cambios requeridos para usar el nuevo juego de caracteres no son triviales:
ROW_FORMAT=DYNAMIC
NOTA: Cambiar a
Barracuda
desdeAntelope
, puede requerir reiniciar el servicio MySQL más de una vez.innodb_file_format_max
no cambia hasta después de que el servicio MySQL se ha reiniciado a:innodb_file_format = barracuda
.MySQL usa el antiguo
Antelope
formato de archivo InnoDB.Barracuda
admite formatos de fila dinámicos, que necesitará si no desea obtener los errores de SQL para crear índices y claves después de cambiar al conjunto de caracteres:utf8mb4
El siguiente escenario se ha probado en MySQL 5.6.17: de forma predeterminada, MySQL está configurado de esta manera:
Detenga su servicio MySQL y agregue las opciones a su my.cnf existente:
Ejemplo de sentencia SQL CREATE:
INDEX contact_idx (contact)
siROW_FORMAT=DYNAMIC
se elimina de la instrucción CREATE.NOTA: Cambiar el índice para limitar a los primeros 128 caracteres
contact
elimina el requisito de usar Barracuda conROW_FORMAT=DYNAMIC
También tenga en cuenta: cuando dice que el tamaño del campo es
VARCHAR(128)
, eso no es 128 bytes. Puede usar 128 caracteres de 4 bytes o 128 caracteres de 1 byte.Esta
INSERT
declaración debe contener el carácter 'poo' de 4 bytes en la fila 2:Puede ver la cantidad de espacio utilizado por la
last
columna:En su adaptador de base de datos, puede configurar el juego de caracteres y la clasificación para su conexión:
En PHP, esto se establecería para:
\PDO::MYSQL_ATTR_INIT_COMMAND
Referencias
fuente
utf8mb4_unicode_520_ci
es mejor. En el futuro, habráutf8mb4_unicode_800_ci
(o algo así), ya que MySQL se pone al día con los estándares Unicode.Las intercalaciones afectan cómo se ordenan los datos y cómo se comparan las cadenas entre sí. Eso significa que debe usar la recopilación que la mayoría de sus usuarios esperan.
Ejemplo de la documentación para charset unicode :
Entonces, depende de su base de usuarios esperada y de cuánto necesita una clasificación correcta . Para una base de usuarios en inglés,
utf8_general_ci
debería ser suficiente, para otros idiomas, como el sueco, se han creado intercalaciones especiales.fuente
Esencialmente, depende de cómo pienses en una cadena.
Siempre uso utf8_bin debido al problema resaltado por Guus. En mi opinión, en lo que respecta a la base de datos, una cadena sigue siendo solo una cadena. Una cadena es un número de caracteres UTF-8. Un personaje tiene una representación binaria, entonces, ¿por qué necesita saber el idioma que está usando? Por lo general, las personas construirán bases de datos para sistemas con el alcance de sitios multilingües. Este es el objetivo de usar UTF-8 como un conjunto de caracteres. Soy un poco purista, pero creo que el riesgo de error supera con creces la ligera ventaja que puede obtener en la indexación. Cualquier regla relacionada con el lenguaje debe hacerse a un nivel mucho más alto que el DBMS.
En mis libros, "valor" nunca debería ser en un millón de años igual a "valúe".
Si quiero almacenar un campo de texto y hacer una búsqueda que no distinga entre mayúsculas y minúsculas, usaré funciones de cadena MYSQL con funciones PHP como LOWER () y la función php strtolower ().
fuente
Para la información textual UTF-8, debe usar
utf8_general_ci
porque ...utf8_bin
: compara cadenas por el valor binario de cada carácter en la cadenautf8_general_ci
: compara cadenas usando reglas de lenguaje general y comparaciones que no distinguen entre mayúsculas y minúsculastambién debería hacer que la búsqueda e indexación de los datos sea más rápida / más eficiente / más útil.
fuente
La respuesta aceptada sugiere de manera bastante definitiva el uso de utf8_unicode_ci, y si bien para proyectos nuevos es genial, quería relatar mi experiencia contraria reciente en caso de que ahorre algo de tiempo a alguien.
Debido a que utf8_general_ci es la clasificación predeterminada para Unicode en MySQL, si desea usar utf8_unicode_ci, entonces tendrá que especificarlo en muchos lugares.
Por ejemplo, todas las conexiones de clientes no solo tienen un conjunto de caracteres predeterminado (tiene sentido para mí) sino también una clasificación predeterminada (es decir, la clasificación siempre será predeterminada a utf8_general_ci para Unicode).
Probablemente, si usa utf8_unicode_ci para sus campos, sus scripts que se conectan a la base de datos deberán actualizarse para mencionar explícitamente la clasificación deseada; de lo contrario, las consultas que usan cadenas de texto pueden fallar cuando su conexión usa la clasificación predeterminada.
El resultado es que al convertir un sistema existente de cualquier tamaño a Unicode / utf8, puede terminar siendo obligado a usar utf8_general_ci debido a la forma en que MySQL maneja los valores predeterminados.
fuente
Para el caso resaltado por Guus, sugeriría encarecidamente usar utf8_unicode_cs (mayúsculas y minúsculas, coincidencia estricta, ordenando correctamente en su mayor parte) en lugar de utf8_bin (coincidencia estricta, orden incorrecta).
Si el campo está destinado a ser buscado, en lugar de coincidir con un usuario, utilice utf8_general_ci o utf8_unicode_ci. Ambos no distinguen entre mayúsculas y minúsculas, uno coincidirá con pérdida ('ß' es igual a 's' y no a 'ss'). También hay versiones específicas del idioma, como utf8_german_ci, donde la coincidencia de pérdida es más adecuada para el idioma especificado.
[Editar - casi 6 años después]
Ya no recomiendo el juego de caracteres "utf8" en MySQL, y en su lugar recomiendo el juego de caracteres "utf8mb4". Coinciden casi por completo, pero permiten un poco (mucho) más caracteres unicode.
Siendo realistas, MySQL debería haber actualizado el conjunto de caracteres "utf8" y las colaciones respectivas para que coincidan con la especificación "utf8", pero en su lugar, un conjunto de caracteres separado y colaciones respectivas para no afectar la designación de almacenamiento para aquellos que ya usan su conjunto de caracteres "utf8" incompleto .
fuente
utf8_unicode_cs
no existe. La única utf8 sensible a mayúsculas y minúsculas esutf8_bin
. El problema es que lautf8_bin
clasificación es incorrecta. Ver: stackoverflow.com/questions/15218077/…Encontré estas tablas de colación útiles. http://collation-charts.org/mysql60/ . Sin embargo, no estoy seguro de cuál es el utf8_general_ci utilizado.
Por ejemplo, aquí está el gráfico para utf8_swedish_ci. Muestra qué caracteres interpreta como iguales. http://collation-charts.org/mysql60/mysql604.utf8_swedish_ci.html
fuente
En el archivo de carga de la base de datos, agregue la siguiente línea antes de cualquier línea:
Y tu problema debería resolverse.
fuente
SET NAMES
consulta directamente no le permite al cliente conocer la codificación y puede romper ciertas características, como las declaraciones preparadas, de una manera muy sutil.