Eu quero alterar uma coluna da tabela de CHAR(2) utf8mb4
para CHAR(2) latin1
(portanto, usará 2 bytes em vez de 8, utf8 não é necessário porque são códigos de país, portanto, há apenas caracteres latinos).
Esta tabela recebe cerca de 50 novas linhas por segundo.
Existem cerca de 125 milhões de linhas, tamanho total da tabela de 5 GB, portanto, a alteração levará um tempo.
Como posso alterar a tabela sem bloquear as gravações?
Questão 1 - Como fazer o
ALTER
sem bloquear tudo muito mal. Resposta: usarpt-online-schema-change
.Problema 2 - Armazenamento para tipos de dados do tipo char.
No passado,
CHAR(n)
sempre reservava n*c bytes, onde c é o tamanho máximo baseado emCHARACTER SET
: 1 para latin1, 3 para utf8, 4 para utf8mb4. Às vezes, isso era útil para Engine=MyISAM com linhas de tamanho FIXO.Em algumas
ROW_FORMATs
versões do InnoDB novas o suficiente (desculpe, não tenho os detalhes),CHAR(n)
ocupará entre n e n * c bytes, dependendo dos caracteres reais necessários. Com o InnoDB, não há conceito de linhas de tamanho fixo.Um complexo
SELECT
que precisa de uma mesa temporária (digamos paraORDER BY
), tentará usar umaMEMORY
mesa para tal. Nesse caso, o comprimento deCHAR(n)
eVARCHAR(n)
sempre será n*c. Isso às vezes leva a uma ineficiência. Ou pode usar MyISAM para a tabela tmp. A versão 8.0 passará a usar o InnoDB para tabelas tmp, portanto, este parágrafo acabará sendo discutível.Converter
CHAR
paraVARCHAR
e/ou converter a coluna de umaCHARACTER SET
para outra requer um serviço pesadoALTER
(nãoINPLACE
). Consulte https://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html Esse link é para 5.6; houve mudanças; escolha a página para a sua versão.VARCHAR
tem 1 ou 2 bytes para o comprimento, mais apenas o número de bytes necessários para os caracteres reais. Então é 1+n*c para short max len.CHAR(2) em UTF8MB é armazenado como VARCHAR(2*4) em latin1. Portanto, você não economizará muito - apenas um byte em um campo de comprimento.
ATUALIZAÇÃO :
Uma mesa
t1
:Com dois registros:
Fica assim no disco:
Vamos dividir.
Registro 1:
0x80000001
isso seria umaINT
chave primária assinada0x000000003109
- ID da transação de seis bytes0xa90000011d0110
- ponteiro de reversão de sete bytes0x7561
- isso seria um valor "ua" em hexadecimal. Dois bytes, não quatro.Os seguintes bytes pertencem ao segundo registro:
0x02
- é um comprimento decountry
valor - dois bytes. O comprimento em si usa um byte porque CHAR(2) pode usar até 2*4 bytes, que é menor que 256.00
-NULL
mapa de valores.country
pode ser NULL, então pelo menos um byte para codificar umNULL
valor.0x000018ffd7
- cinco bytes do chamado campo "extra bytes".0x80000002
- chave primária do segundo registro - dois.0x00000000310a
-trx_id
0xaa0000011e0110
-roll_ptr
0x7573
- "nós"Então, esse foi um formato
COMPACT
eDYNAMIC
.Vamos fazer o mesmo exercício para
REDUNDANT
o formato - o formato InnoDB mais antigo disponível desde as versões 4.0.*+Diferenças: