Gostaria de saber se existe uma "melhor" opção de agrupamento no MySQL para um site geral em que você não tem 100% de certeza do que será inserido? Eu entendo que todas as codificações devem ser as mesmas, como MySQL, Apache, HTML e qualquer coisa dentro do PHP.
No passado, eu configurei o PHP para saída em "UTF-8", mas qual agrupamento isso corresponde no MySQL? Eu estou pensando que é um dos UTF-8 queridos, mas eu usei utf8_unicode_ci
, utf8_general_ci
e utf8_bin
antes.
Respostas:
A principal diferença é a precisão da classificação (ao comparar caracteres no idioma) e o desempenho. O único especial é utf8_bin, que serve para comparar caracteres em formato binário.
utf8_general_ci
é um pouco mais rápido queutf8_unicode_ci
, mas menos preciso (para classificação). A codificação utf8 de idioma específico (comoutf8_swedish_ci
) contém regras de idioma adicionais que os tornam mais precisos para ordenar para esses idiomas. Na maioria das vezes eu usoutf8_unicode_ci
(prefiro precisão a pequenas melhorias de desempenho), a menos que tenha um bom motivo para preferir um idioma específico.Você pode ler mais sobre conjuntos de caracteres unicode específicos no manual do MySQL - http://dev.mysql.com/doc/refman/5.0/en/charset-unicode-sets.html
fonte
utf8_unicode_*
utf8mb4
eutf8mb4_unicode_520_ci
. Eles oferecem o restante dos chineses, além de agrupamento aprimorado.Na verdade, você provavelmente deseja usar
utf8_unicode_ci
ouutf8_general_ci
.utf8_general_ci
classifica removendo todos os sotaques e classificando como se fosse ASCIIutf8_unicode_ci
usa a ordem de classificação Unicode, para classificar corretamente em mais idiomasNo entanto, se você estiver usando apenas isso para armazenar texto em inglês, eles não deverão diferir.
fonte
Esteja muito, muito ciente deste problema que pode ocorrer ao usar
utf8_general_ci
.O MySQL não fará distinção entre alguns caracteres nas instruções de seleção, se o
utf8_general_ci
agrupamento for usado. Isso pode levar a erros muito desagradáveis - especialmente por exemplo, onde nomes de usuários estão envolvidos. Dependendo da implementação que usa as tabelas do banco de dados, esse problema pode permitir que usuários mal-intencionados criem um nome de usuário correspondente a uma conta de administrador.Esse problema se expõe no mínimo nas versões 5.x iniciais - não tenho certeza se esse comportamento foi alterado posteriormente.
Eu não sou DBA, mas para evitar esse problema, eu sempre o uso, em
utf8-bin
vez de não diferenciar maiúsculas de minúsculas.O script abaixo descreve o problema pelo exemplo.
fonte
'value'
e'valUe'
. O ponto principal de um agrupamento é que ele fornece regras para (entre outras coisas) quando duas cadeias são consideradas iguais uma à outra.É melhor usar o conjunto de caracteres
utf8mb4
com o agrupamentoutf8mb4_unicode_ci
.O conjunto de caracteres,
utf8
suporta apenas uma pequena quantidade de pontos de código UTF-8, cerca de 6% dos caracteres possíveis.utf8
suporta apenas o plano multilíngue básico (BMP). Existem outros 16 aviões. Cada plano contém 65.536 caracteres.utf8mb4
suporta todos os 17 aviões.O MySQL truncará caracteres UTF-8 de 4 bytes, resultando em dados corrompidos.
O
utf8mb4
conjunto de caracteres foi introduzido no MySQL 5.5.3 em 24-03-2010.Algumas das alterações necessárias para usar o novo conjunto de caracteres não são triviais:
ROW_FORMAT=DYNAMIC
NOTA: Mudar para
Barracuda
deAntelope
, pode exigir a reinicialização do serviço MySQL mais de uma vez.innodb_file_format_max
não muda até que o serviço MySQL foi reiniciado para:innodb_file_format = barracuda
.O MySQL usa o antigo
Antelope
formato de arquivo InnoDB.Barracuda
suporta formatos de linha dinâmicos, que você precisará se não desejar obter os erros do SQL para criar índices e chaves após mudar para o conjunto de caracteres:utf8mb4
O cenário a seguir foi testado no MySQL 5.6.17: Por padrão, o MySQL está configurado assim:
Pare o serviço MySQL e adicione as opções ao my.cnf existente:
Instrução SQL CREATE de exemplo:
INDEX contact_idx (contact)
seROW_FORMAT=DYNAMIC
for removido da instrução CREATE.NOTA: Alterar o índice para limitar os primeiros 128 caracteres
contact
elimina o requisito de usar o Barracuda comROW_FORMAT=DYNAMIC
Observe também: quando diz que o tamanho do campo é
VARCHAR(128)
, isso não é 128 bytes. Você pode usar caracteres de 128, 4 bytes ou 128, caracteres de 1 byte.Esta
INSERT
declaração deve conter o caractere 'poo' de 4 bytes na linha 2:Você pode ver a quantidade de espaço usada pela
last
coluna:No seu adaptador de banco de dados, convém definir o conjunto de caracteres e agrupamento para sua conexão:
No PHP, isso seria definido para:
\PDO::MYSQL_ATTR_INIT_COMMAND
Referências:
fonte
utf8mb4_unicode_520_ci
é melhor. No futuro, haveráutf8mb4_unicode_800_ci
(ou algo parecido), já que o MySQL alcança os padrões Unicode.Os agrupamentos afetam como os dados são classificados e como as seqüências de caracteres são comparadas entre si. Isso significa que você deve usar o agrupamento que a maioria de seus usuários espera.
Exemplo da documentação para charset unicode :
Portanto, depende da sua base de usuários esperada e de quanto você precisa da classificação correta . Para uma base de usuários em inglês,
utf8_general_ci
deve ser suficiente. Para outros idiomas, como o sueco, foram criados agrupamentos especiais.fonte
Basicamente, depende de como você pensa em uma string.
Eu sempre uso utf8_bin por causa do problema destacado por Guus. Na minha opinião, no que diz respeito ao banco de dados, uma string ainda é apenas uma string. Uma sequência é um número de caracteres UTF-8. Um personagem tem uma representação binária. Por que ele precisa saber o idioma que você está usando? Geralmente, as pessoas estão construindo bancos de dados para sistemas com o escopo de sites multilíngues. Esse é o objetivo de usar UTF-8 como um conjunto de caracteres. Sou um pouco purista, mas acho que os riscos do bug superam fortemente a pequena vantagem que você pode obter na indexação. Quaisquer regras relacionadas ao idioma devem ser feitas em um nível muito superior ao DBMS.
Nos meus livros, "valor" nunca deve em um milhão de anos ser igual a "valor".
Se eu quiser armazenar um campo de texto e fazer uma pesquisa sem distinção entre maiúsculas e minúsculas, usarei funções de string MYSQL com funções PHP como LOWER () e a função php strtolower ().
fonte
Para informações textuais UTF-8, você deve usar
utf8_general_ci
porque ...utf8_bin
: compare cadeias pelo valor binário de cada caractere na cadeiautf8_general_ci
: compare cadeias usando regras gerais de linguagem e comparações que não diferenciam maiúsculas de minúsculasaka ele deve tornar a pesquisa e a indexação dos dados mais rápidas / eficientes / mais úteis.
fonte
A resposta aceita sugere definitivamente definitivamente o uso de utf8_unicode_ci e, embora para novos projetos seja ótimo, eu queria relacionar minha experiência contrária recente, para o caso de economizar algum tempo para alguém.
Como utf8_general_ci é o agrupamento padrão para Unicode no MySQL, se você deseja usar utf8_unicode_ci, acaba tendo que especificá-lo em muitos lugares.
Por exemplo, todas as conexões do cliente não apenas têm um conjunto de caracteres padrão (faz sentido para mim), mas também um agrupamento padrão (ou seja, o agrupamento sempre será o padrão utf8_general_ci para unicode).
Provavelmente, se você usar utf8_unicode_ci para seus campos, seus scripts que se conectam ao banco de dados precisarão ser atualizados para mencionar explicitamente o agrupamento desejado - caso contrário, as consultas usando cadeias de texto poderão falhar quando sua conexão estiver usando o agrupamento padrão.
O resultado é que, ao converter um sistema existente de qualquer tamanho para Unicode / utf8, você pode acabar sendo forçado a usar utf8_general_ci devido à maneira como o MySQL lida com os padrões.
fonte
Para o caso destacado por Guus, eu sugeriria fortemente o uso de utf8_unicode_cs (correspondência estrita entre maiúsculas e minúsculas, ordenação correta na maioria das vezes) em vez de utf8_bin (correspondência estrita, ordenação incorreta).
Se o campo pretender ser pesquisado, em vez de correspondente a um usuário, use utf8_general_ci ou utf8_unicode_ci. Ambos não fazem distinção entre maiúsculas e minúsculas, um corresponderá perdidamente ('ß' é igual a 's' e não a 'ss'). Também existem versões específicas do idioma, como utf8_german_ci, em que a correspondência perdida é mais adequada para o idioma especificado.
[Editar - quase 6 anos depois]
Eu não recomendo mais o conjunto de caracteres "utf8" no MySQL e, em vez disso, recomendo o conjunto de caracteres "utf8mb4". Eles correspondem quase inteiramente, mas permitem um pouco (muito) de caracteres unicode.
Realisticamente, o MySQL deveria ter atualizado o conjunto de caracteres "utf8" e respectivos agrupamentos para corresponder à especificação "utf8", mas, em vez disso, um conjunto de caracteres separado e respectivos agrupamentos para não afetar a designação de armazenamento para aqueles que já usam seu conjunto de caracteres "utf8" incompleto .
fonte
utf8_unicode_cs
não existe. O único utf8 que diferencia maiúsculas de minúsculas éutf8_bin
. O problema estáutf8_bin
classificando incorreto. Veja: stackoverflow.com/questions/15218077/…Achei esses gráficos de agrupamento úteis. http://collation-charts.org/mysql60/ . Não sei ao certo qual é o utf8_general_ci usado.
Por exemplo, aqui está o gráfico para utf8_swedish_ci. Mostra quais caracteres ele interpreta como o mesmo. http://collation-charts.org/mysql60/mysql604.utf8_swedish_ci.html
fonte
No arquivo de upload do banco de dados, adicione a linha a seguir antes de qualquer linha:
E seu problema deve ser resolvido.
fonte
SET NAMES
direta de uma consulta não informa o cliente sobre a codificação e pode interromper alguns recursos, como instruções preparadas, de maneira muito sutil.