O Latin-1 deve ser usado sobre UTF-8 quando se trata de configuração de banco de dados?

65

Estamos usando o MySQL na empresa em que trabalho e criamos aplicativos internos e voltados para o cliente usando o Ruby on Rails.

Quando comecei a trabalhar aqui, tive um problema que nunca havia encontrado antes; o banco de dados no servidor de produção está definido como Latin-1, o que significa que a jóia do MySQL lança uma exceção sempre que houver entrada do usuário em que o usuário copie e cole caracteres UTF-8.

Meu chefe chama esses "caracteres ruins", pois a maioria deles são caracteres não imprimíveis e diz que precisamos removê-los. Eu encontrei algumas maneiras de fazer isso, mas eventualmente acabamos em uma circunstância em que um caractere UTF-8 era necessário. Além disso, é um pouco complicado, especialmente porque parece que a única solução que eu já li sobre esse problema é definir o banco de dados como UTF-8 (faz sentido para mim).

O único argumento que ouvi sobre o Latin-1 é que permitir caracteres UTF-8 não imprimíveis pode atrapalhar as pesquisas de texto / texto completo no MySQL. Isso é mesmo verdade?

Existem outras razões pelas quais alguém deve usar o Latin-1 em vez do UTF-8? Entendo que é superior e se torna mais onipresente.

Ravenstine
fonte
4
@jon LATIN-1 não é específico em inglês. O espanhol está perfeitamente contido, assim como o francês, se não me engano.
Darkhogg
4
@Darkhog: Latin1 não é realmente específico para o inglês, mas é essencialmente restrito aos alfabetos da Europa Ocidental.
Bart van Ingen Schenau
16
O único benefício possível do uso do Latin 1 em vez do UTF-8 em um sistema moderno é a sabotagem. É claro que isso é apenas um benefício para o sabotador e para quem quer que seja sua lealdade, não para os proprietários ou desenvolvedores do sistema.
Jon Hanna
13
Pena que seu banco de dados não seria capaz de conter o símbolo do Euro ou mesmo o meu nome (דותן).
dotancohen
20
usuário "copiar e colar" caracteres não latinos-1? não trate o unicode como algo irrelevante e frívolo com o qual apenas nerds travessos se importam. um monte de gente digitar caracteres que não cabem em Latim-1 em uma base regular - eu ouço um monte de pessoas falam línguas não europeias, mesmo ♥
Eevee

Respostas:

131

O Unicode é certamente difícil, e a codificação UTF-8 possui algumas propriedades inconvenientes. No entanto, o UTF-8 se tornou a codificação padrão de fato na Web, superando o ASCII, Latin-1, UCS-2 e UTF-16. Basta usar UTF-8 em qualquer lugar .

A razão mais importante pela qual você deve dar suporte ao Unicode é que você não deve fazer suposições desnecessárias sobre a entrada do usuário. Não tenho idéia de qual é o seu domínio, mas coisas como nomes de usuário hebraicos, uma postagem no blog sobre a China, um comentário com Emoji ou texto bem estilizado - como "this" - devem ser possíveis ... Ah, essas eram aspas tipograficamente corretas ( “”em vez de ""), traços inteiros e reticências, que são caracteres comuns no texto em inglês, mas não são suportados pelo ASCII ou pelo Latin-1. Portanto, não dar suporte a outros scripts não é apenas um grande problema para outras culturas, mas aderir ao Latin-1 nem permite que você escreva um inglês adequado.

A noção de que o Unicode permite apenas "caracteres inválidos" está errada. Sim, o texto é realmente complicado e o Unicode não esconde isso de você. Seu chefe pode estar pensando em caracteres compostos, onde um ponto de código base, como aé modificado por pontos de código subseqüentes que, por exemplo, representam diacríticos para formar um caractere visual, como á. Isso realmente não entra no seu caminho ao tentar fazer pesquisas se você fizer algum tipo de normalização. Por exemplo, você pode armazenar todo o texto no formulário NFC que recolhe essas composições na forma pré-composta, se houver uma disponível. Ao pesquisar, você também pode retirar todos os caracteres de composição do texto, mas isso pode alterar substancialmente o significado em alguns idiomas.

O Unicode também adiciona muitos caracteres não imprimíveis - mas até o ASCII possui muitos deles. Você vai lidar com um NUL no meio de uma string? Que tal 0x1C, um "Separador de Arquivos"? Eu nunca vi metade disso . O Latin-1 adiciona um hífen suave que indica oportunidades de quebra de palavras, mas é invisível. Isso também interrompe sua pesquisa de texto completo? Em outras palavras, até o ASCII e o Latin-1 permitem que você quebre completamente sua entrada se você assumir que tudo é apenas texto imprimível!

amon
fonte
8
Do ponto de vista do banco de dados, alguns desses caracteres não são / não devem ser permitidos em um campo de tipo de texto (text / varchar / char / etc.). MySQL não permitir caracteres nulos nestes tipos de dados, mas outras bases de dados como PostgreSQL não. Você deveria usar BLOB (MySQL) ou BYTEA (PostgreSQL) se quiser poder armazenar esses caracteres.
Cimmanon
15
"aderir ao Latin-1 nem permite que você escreva um inglês adequado" Isso é bom, caso contrário, o unicode seria resistido ainda mais. ;-)
Eliminador de duplicadores
3
@ PaŭloEbermann Os caracteres NUL incorporados significam que seus dados são um blob binário, não apenas uma string. NULs foi um exemplo estranho, pois acredito que o UTF-8 evita o uso de um \0byte como parte de uma codificação de vários bytes, para garantir que o código não compatível com o UTF8 não pare no meio de uma string.
Peter Cordes
7
Todos os caracteres Unicode são imprimíveis - você só precisa a fonte correta :-)
James Anderson
4
@ JamesAnderson, a fonte estaria errada e quebrada. pt.wikipedia.org/wiki/Unicode_control_characters
djechlin 02/02
62

Penso que além da questão técnica, seu chefe pode não ter tempo para se manter atualizado sobre os padrões atuais.

Como sua posição não está completamente fora do almoço, apenas desatualizada, respeite sua posição ao discutir esse assunto (e você precisa se lembrar de discutir , não discuta) e tente resolver as preocupações que ele tem com relação à UTF-8. Suspeito que o problema subjacente não seja técnico e possa exigir algum nível de negociação de habilidades pessoais.

Nelson
fonte
6
Não pude aprovar mais. Na verdade, lamento que, em minha própria resposta, tenha ignorado completamente o "lado humano", que nesta edição poderia ser fundamental. Gostaria de poder upvote mais de uma vez :-)
LSerni
2
chamando tudo fora do latin-1 bad charactere pensando que é isso non-printableé just out-datedpara você?
Njzk2
2
A verdadeira questão é: "É uma questão técnica com a qual estamos lidando?" Não acredito que o chefe do OP tenha estudado e aprendido isso, ou leu algum manual / diário técnico e cheguei a essa conclusão. Não acho que a solução seja estritamente técnica. Ironicamente, o comentário mostra exatamente o cerne da questão; resolver esse problema pode ser extremamente ofensivo se for feito de maneira inadequada.
187 Nelson Nelson
49

Qual de nós está certo?

Era uma vez, seu chefe era. Mas com o passar do tempo, as coisas mudam. Atualmente você é (mas antes de correr para o seu chefe, não deixe de ler a resposta de Nelson também ).

As versões antigas do MySQL, e as versões antigas de quase tudo , lidavam muito melhor com o Latin1 / ISO-8859-1 (5) mais antigo que o UTF8.

Há uma razão pela qual o UTF8 foi criado, evoluído e promovido principalmente em todos os lugares: se implementado corretamente, funciona muito melhor . Existem alguns problemas de desempenho e armazenamento decorrentes do fato de um caractere Latin1 ter 8 bits, enquanto um caractere UTF8 pode ter de 8 a 32 bits. Portanto, ao planejar, VARCHARé necessário levar isso em consideração. E suas rotinas de pesquisa serão um pouco mais lentas. Eles serão capazes de fazer mais coisas (por exemplo, pesquisas com sensibilidade acento ou sem . Não pode fazer aqueles em Latin1 sem um extenso trabalho), mas vai demorar um pouco mais tempo.

Mas, por outro lado, o armazenamento é barato , a sobrecarga realista do tamanho dos arquivos é inferior a 2-3%, o poder da computação também é barato e fica mais barato de acordo com a Lei de Moore; enquanto seu tempo e as expectativas de seus clientes definitivamente não são .

Você pode ter que se preocupar para ferramentas de busca etc. se você fosse o único a desenvolver essas ferramentas. Mas você provavelmente não é. Você usa essas ferramentas; mesmo aqueles que não eram completamente compatíveis com UTF8 ontem (como os MySQLs anteriores não eram), são hoje ou serão em breve (por exemplo, MySQL com suporte a utf8mb4).

Portanto, planejando e implementando cuidadosamente o UTF8 da maneira certa ( sem pensar no Latin1 como uma reflexão tardia), você pode ter um código razoavelmente à prova de futuro , o que, se você planeja fazer negócios com qualquer país asiático, é muito bom Coisa. E se você não tiver esses planos, outras pessoas terão, e elas poderão ser seus clientes, fornecedores ou parceiros.

Portanto, quando eles começarem a enviar dados UTF8, você precisará configurar um procedimento complicado para converter para o Latin1 e lidar com casos insolúveis.

Quando você leva em consideração no orçamento o custo de várias escaramuças contra os ninjas do mojibake , e considera que eles não vão desaparecer - como você já descobriu -, você perceberá que usar o UTF8 não é apenas mais simples, mas sim mais barato também.

LSerni
fonte
4

Algumas situações em que a restrição do conjunto de caracteres apenas para ASCII pode fazer sentido são para campos de escolha limitada, por exemplo, campos de status, porque você controla estritamente os valores que podem estar lá e chaves / referências estrangeiras ao sistema externo, porque raramente existem razões para eles têm apenas caracteres alfanuméricos e alguns símbolos.

Para outros textos, basta usar UTF-8.

Lie Ryan
fonte
2
O MySQL não tem enumerações?
Raptortech97
2
E como o ASCII é um subconjunto do UTF8, use o UTF8 mesmo assim.
RemcoGerlich 02/02
@RemcoGerlich: Não concordo que você possa usar o UTF8 para eles. Na minha opinião, as referências externas não são texto, mas uma sequência opaca de bytes. Eles não têm charset, exceto por conveniência notacional. Se a sequência de bytes tiver uma interpretação em determinado conjunto de caracteres, ou seja, o domínio do sistema externo ou do aplicativo, não o banco de dados.
Lie Ryan
3
@ LiRyan: Entendo esse ponto, mas também não deve ser ASCII, provavelmente algum formato de blob binário ou mais.
RemcoGerlich 02/02
3

Para começar com a resposta, não importa como o servidor está configurado. A codificação de caracteres no MySQL pode ser configurada por coluna (significa que a mesma tabela pode conter caracteres em várias codificações, fácil). Ou seja, meu servidor (e vários bancos de dados herdados) está configurado para cp1251 por padrão para clientes antigos que não conseguem definir o agrupamento correto na conexão (clientes de hardware diferentes), mas os principais bancos de dados em produção estão usando UTF-8.

Falando em "espaço desperdiçado" - você não pode realisticamente chamar dados importantes de lixo, pode? O aumento do espaço de armazenamento, no entanto, será diferente dependendo do idioma em que seus dados estiverem. Desde um aumento insignificante (menos de 1%) se o site estiver principalmente em inglês e até 100%, se estiver usando caracteres fora do intervalo ASCII . E ainda mais, se você se mudar para o leste. As especificações UTF-8 posteriores (chamadas UTF8mb4) permitem até 4 bytes por ponto de código.

E para "quem está certo" ... A verdade é que essa é uma questão social mais do que técnica. Pode haver razões válidas para configurações específicas do servidor, mas você deve conhecer as implicações. Mas se você me perguntar, não há razão para não usar UTF-8. É o único tipo de governar todos os textos do mundo.

AnrDaemon
fonte
O MySQL tentará converter dados na codificação de banco de dados antes de convertê-los em codificação de coluna. Se você possui utf8 client, latin1 database e utf8 columnt, os dados de texto podem ser perdidos.
Ivan Solntsev 02/02
Ivan, essa é uma pergunta totalmente diferente. A interação entre o conjunto de caracteres cliente, o conjunto de caracteres do servidor, a conexão do conjunto de caracteres e o resultado do conjunto de caracteres é um longo artigo na documentação do MySQL. E, no caso de configurações de agrupamento por coluna, "agrupamento de banco de dados" é agrupamento de colunas e é diretamente convertido em resultado do conjunto de caracteres, ignorando o agrupamento de bancos de dados.
AnrDaemon
0

Apenas explique a ele que UTF-8 é o padrão para o tráfego da web. E qualquer usuário pode inserir qualquer caractere unicode válido em seu navegador.

É muito mais fácil ter utf-8 / unicode todo o caminho, do front-end ao back-end, do que lidar com os diversos e diversos problemas resultantes do utf-8-> latin-1-> utf-8.

James Anderson
fonte