É útil entender as seguintes definições:
-
Uma codificação de caracteres detalha como cada símbolo é representado em binário (e, portanto, armazenado no computador). Por exemplo, o símboloé
(U+00E9, letra minúscula E latina com agudo) é codificado como0xc3a9
em UTF-8 (que o MySQL chamautf8
) e0xe9
em Windows-1252 (que o MySQL chama delatin1
).
-
Um conjunto de caracteres é o alfabeto de símbolos que podem ser representados usando uma determinada codificação de caracteres. Confusamente, o termo também é usado para significar o mesmo que codificação de caracteres.
-
Uma coleção é uma ordenação em um conjunto de caracteres, para que as strings possam ser comparadas. Por exemplo:latin1_swedish_ci
do MySQL collation trata as variações mais acentuadas de um caractere como equivalente ao caractere base, enquanto seulatin1_general_ci
collation irá ordená-los antes do próximo caractere base, mas não equivalente (há outras diferenças mais significativas também:como a ordem dos caracteres comoå
,ä
,ö
eß
).
O MySQL decidirá qual agrupamento deve ser aplicado a uma determinada expressão conforme documentado em Agrupamento de expressões :em particular, o agrupamento de uma coluna tem precedência sobre o de um literal de string.
O
WHERE
cláusula da sua consulta compara as seguintes strings:-
um valor emfos_user.username
, codificado no conjunto de caracteres da coluna (Windows-1252) e expressando uma preferência por seu agrupamentolatin1_swedish_ci
(com um valor de coercibilidade de 2); com
-
a string literal'Nrv⧧Kasi'
, codificado no conjunto de caracteres da conexão (UTF-8, conforme configurado pelo Doctrine) e expressando preferência pelo agrupamento da conexãoutf8_general_ci
(com um valor de coercibilidade de 4).
Como a primeira dessas strings tem um valor de coercibilidade menor que a segunda, o MySQL tenta realizar a comparação usando o agrupamento dessa string:
latin1_swedish_ci
. Para fazer isso, o MySQL tenta converter a segunda string para latin1
—mas desde o ⧧
caractere não existir nesse conjunto de caracteres, a comparação falhará. Aviso
Deve-se fazer uma pausa por um momento para considerar como a coluna está atualmente codificada:você está tentando filtrar registros onde
fos_user.username
é igual a uma string que contém um caractere que não pode existe nessa coluna ! Se você acredita que a coluna sim contém esses caracteres, então você provavelmente escreveu na coluna enquanto a codificação do caractere de conexão estava definida para algo (por exemplo,
latin1
) que fez com que o MySQL interpretasse a sequência de bytes recebida como caracteres que estão todos no conjunto de caracteres Windows-1252. Se este for o caso, antes de continuar, você deve corrigir seus dados!
-
converter essas colunas para a codificação de caracteres que foi usada na inserção de dados, se diferente da codificação incumbente:
ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET foo;
-
elimine as informações de codificação associadas a essas colunas convertendo-as para obinary
conjunto de caracteres:
ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET binary;
-
associe a essas colunas a codificação na qual os dados foram realmente transmitidos, convertendo-os no conjunto de caracteres relevante.
ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET bar;
Observe que, se estiver convertendo de uma codificação multibyte, pode ser necessário aumentar o tamanho da coluna (ou até mesmo alterar seu tipo) para acomodar o comprimento máximo possível da string convertida.
Uma vez que se tenha certeza de que as colunas estão codificadas corretamente, pode-se forçar a comparação a ser realizada usando um agrupamento Unicode por:
-
convertendo explicitamente o valorfos_user.username
para um conjunto de caracteres Unicode:
WHERE CONVERT(fos_user.username USING utf8) = ?
-
forçando a string literal a ter um valor de coercibilidade menor que a coluna (causará uma conversão implícita do valor da coluna para UTF-8):
WHERE fos_user.username = ? COLLATE utf8_general_ci
Ou pode-se, como você diz, converter permanentemente as colunas em uma codificação Unicode e definir seu agrupamento adequadamente.
A principal consideração é que as codificações Unicode ocupam mais espaço do que conjuntos de caracteres de byte único, portanto:
-
mais armazenamento pode ser necessário;
-
as comparações podem ser mais lentas; e
-
os comprimentos do prefixo do índice podem precisar ser ajustados (observe que o máximo está em bytes, portanto, pode representar menos caracteres do que anteriormente).
Além disso, esteja ciente de que, conforme documentado em
ALTER TABLE
Sintaxe
: