Desenvolvimento e bases de dados

Converter uma base de dados de utf8 para utf8mb4

Revisto a 8 min de leitura MySQL codificação

Uma aplicação antiga pode exigir a conversão das suas tabelas de utf8 para utf8mb4. Não faça substituições globais num dump nem elimine as tabelas de produção: uma substituição de texto pode alterar dados de utilizadores, nomes de collations não equivalentes ou conteúdo serializado.

1. Criar e verificar uma cópia protegida

Trabalhe a partir de uma pasta privada fora de public_html, com um nome de dump novo. Pare temporariamente as escritas da aplicação e gere um dump consistente. -p pede a palavra-passe de forma interativa e evita deixá-la no histórico ou na lista de processos:

umask 077
mysqldump --single-transaction --routines --triggers -u USUARIO_MYSQL -p BASE_DE_DATOS > base-antes-utf8mb4.sql &&
test -s base-antes-utf8mb4.sql &&
sha256sum base-antes-utf8mb4.sql > base-antes-utf8mb4.sql.sha256 &&
chmod 400 base-antes-utf8mb4.sql base-antes-utf8mb4.sql.sha256 &&
sha256sum -c base-antes-utf8mb4.sql.sha256

Se o mysqldump devolver um erro, não continue nem considere válido o ficheiro parcial. A exportação de rotinas exige permissões; se falhar, reveja que objetos a aplicação precisa antes de os omitir. Os eventos, se existirem, também têm de ser inventariados e exportados com as opções e permissões adequadas. O checksum deteta alterações posteriores no ficheiro, mas não demonstra que a cópia está completa. As permissões só de leitura também não a tornam imutável.

Descarregue também ambos os ficheiros para um armazenamento diferente do alojamento. Não edite este dump: será o ponto de recuperação.

2. Restaurar numa base de dados nova

Crie uma base de dados vazia, com outro utilizador e outro nome, e restaure aí a cópia:

mysql -u USUARIO_NUEVO -p BASE_NUEVA < base-antes-utf8mb4.sql

Desative no clone os emails, cobranças, webhooks e tarefas automáticas de produção. Configure um clone da aplicação para usar BASE_NUEVA e confirme que abre, inicia sessão e executa as suas operações principais antes de converter o que quer que seja.

3. Pré-visualizar e converter o clone

Consulte primeiro as tabelas cujo valor predefinido continua a ser utf8 ou utf8mb3:

SELECT TABLE_NAME, TABLE_COLLATION
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'BASE_NUEVA'
  AND (
      TABLE_COLLATION LIKE 'utf8mb3\_%'
      OR TABLE_COLLATION LIKE 'utf8\_%'
  );

A codificação de uma coluna pode ser diferente da predefinida da sua tabela. Reveja também as colunas; uma tabela com valor predefinido utf8mb4 ainda pode conter colunas antigas:

SELECT TABLE_NAME, COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'BASE_NUEVA'
  AND CHARACTER_SET_NAME IS NOT NULL
ORDER BY TABLE_NAME, ORDINAL_POSITION;

O gerador seguinte é um ponto de partida para as tabelas que a primeira lista mostra. CONVERT TO transforma todas as suas colunas de texto, incluindo as que tenham uma codificação diferente; não o execute sem rever essas exceções. Se só for preciso alterar algumas colunas, prepare um ALTER TABLE ... MODIFY que mantenha a sua definição completa.

Gere as instruções exatas de que precisaria, reveja-as uma a uma e execute-as apenas sobre BASE_NUEVA:

SELECT CONCAT(
    'ALTER TABLE `', REPLACE(TABLE_SCHEMA, '`', '``'),
    '`.`', REPLACE(TABLE_NAME, '`', '``'),
    '` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'
) AS sentencia_a_revisar
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'BASE_NUEVA'
  AND TABLE_TYPE = 'BASE TABLE'
  AND (
      TABLE_COLLATION LIKE 'utf8mb3\_%'
      OR TABLE_COLLATION LIKE 'utf8\_%'
  );

O MySQL 8 mostra normalmente as collations do antigo utf8 com o nome utf8mb3; o segundo padrão mantém a compatibilidade com versões que ainda mostram o alias anterior. A collation concreta tem de ser compatível com a versão do MySQL e com a aplicação. Verifique que a collation escolhida existe no destino. Mudar as regras de comparação pode gerar coincidências novas em índices únicos; a conversão também pode alargar tipos de texto ou entrar em conflito com chaves estrangeiras. Reveja previamente os índices de colunas de texto, porque, ao aumentar o tamanho máximo por carácter, alguns índices antigos podem exceder o limite admitido.

Se quiser que as tabelas novas herdem utf8mb4, altere também o valor predefinido da base de dados clonada:

ALTER DATABASE `BASE_NUEVA`
  CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Isto não converte as tabelas existentes. Configure também utf8mb4 no conector da aplicação; alterar apenas o esquema não garante que consiga escrever caracteres de quatro bytes. --single-transaction proporciona um instantâneo consistente para tabelas transacionais, mas não protege tabelas MyISAM nem alterações de esquema durante o dump.

4. Validar e mudar a aplicação

Compare entre a base de dados original e o clone:

  • esquema, índices, vistas, triggers e rotinas;
  • contagem de linhas de cada tabela;
  • amostras com acentos, caracteres de quatro bytes e conteúdo serializado;
  • acesso, pesquisas, edição e tarefas agendadas da aplicação.

Quando todas as verificações estiverem corretas, volte a parar as escritas, repita no clone as alterações produzidas desde o primeiro dump, se for necessário, e altere as credenciais da aplicação para apontar para a base de dados nova. Mantenha a base de dados original intacta e sem escritas durante o período de observação.

Reversão

Se a validação posterior falhar, pare as escritas e identifique as operações recebidas na base de dados nova. Decida como as guardar antes de voltar à original: alterar apenas as credenciais perderia essas alterações. Depois, reponha as credenciais anteriores e valide a aplicação. Não elimine a base de dados original nem o dump verificado até encerrar expressamente o período de recuperação.

Se tiver dúvidas sobre a collation adequada ou sobre como sincronizar as escritas finais, contacte o suporte antes da mudança.

Também lhe pode ser útil

Algo não bate certo ou mudou? Diga-nos e revemos.