Eu tenho uma tabela InnoDB que quero alterar. A tabela tem cerca de 80 milhões de linhas e encerra alguns índices.
Quero mudar o nome de uma das colunas e adicionar mais alguns índices.
- Qual é a maneira mais rápida de fazer isso (supondo que eu possa sofrer até mesmo tempo de inatividade - o servidor é um escravo não utilizado)?
- É um "simples"
alter table
, a solução mais rápida?
Neste momento, tudo o que me importa é a velocidade :)
Uma maneira segura de acelerar um ALTER TABLE é remover índices desnecessários
Aqui estão os passos iniciais para carregar uma nova versão da tabela
Por favor observe o seguinte:
Eu larguei source_persona_index porque é a primeira coluna em 4 outros índices
Eu larguei target_persona_index porque é a primeira coluna em 2 outros índices
Eu larguei target_persona_relation_type_index porque as 2 primeiras colunas também estão em target_persona_relation_type_message_id_index
OK Isso cuida de índices desnecessários. Existem índices com baixa cardinalidade? Aqui está a maneira de determinar isso:
Execute as seguintes consultas:
De acordo com sua pergunta, existem cerca de 80.000.000 de linhas. Como regra geral, o MySQL Query Optimizer não usará um índice se a cardinalidade das colunas selecionadas for maior que 5% da contagem de linhas da tabela. Nesse caso, seriam 4.000.000.
COUNT(DISTINCT sent_at)
> 4.000.000ALTER TABLE s_relations_new DROP INDEX sent_at_index;
COUNT(DISTINCT message_id)
> 4.000.000ALTER TABLE s_relations_new DROP INDEX message_id_index;
COUNT(DISTINCT target_object_id)
> 4.000.000ALTER TABLE s_relations_new DROP INDEX target_object_index;
Uma vez determinada a utilidade ou inutilidade desses índices, você pode recarregar os dados
É isso, certo? NÃO !!!
Se seu site esteve ativo todo esse tempo, pode haver INSERTs sendo executados em s_relations durante o carregamento de s_relations_new. Como você pode recuperar essas linhas ausentes?
Vá encontrar o id máximo em s_relations_new e anexe tudo depois desse ID de s_relations. Para garantir que a tabela seja congelada e usada apenas para esta atualização, você deve ter um pouco de tempo de inatividade para obter as últimas linhas que foram inseridas em s_relation_new. Aqui está o que você faz:
No sistema operacional, reinicie o mysql para que ninguém mais possa fazer login, exceto root@localhost (desativa o TCP/IP):
Em seguida, faça login no mysql e carregue essas últimas linhas:
Em seguida, reinicie o mysql normalmente
Agora, se você não pode derrubar o mysql, você terá que fazer um bait-and-switch em s_relations. Basta acessar o mysql e fazer o seguinte:
De uma chance !!!
CAVEAT : Quando estiver satisfeito com esta operação, você pode descartar a tabela antiga assim que possível:
A resposta correta depende da versão do mecanismo MySQL que você está usando.
Se estiver usando 5.6+, as renomeações e a adição/remoção de índices são realizadas online , ou seja, sem copiar todos os dados da tabela.
Basta usar
ALTER TABLE
como de costume, será principalmente instantâneo para renomeações e quedas de índice e razoavelmente rápido para adição de índice (tão rápido quanto ler toda a tabela uma vez).Se estiver usando 5.1+ e o plug-in InnoDB estiver ativado, a adição/remoção de índices também estará online. Não tenho certeza sobre renomeações.
Se estiver usando uma versão mais antiga,
ALTER TABLE
ainda é a mais rápida, mas provavelmente será terrivelmente lenta porque todos os seus dados serão reinseridos em uma tabela temporária sob o capô.Finalmente, hora de desmascarar os mitos. Infelizmente não tenho carma suficiente aqui para comentar as respostas, mas sinto que é importante corrigir a resposta mais votada. Isso está errado :
Na verdade é o contrário .
Os índices são úteis para selecionar poucas linhas, por isso é importante que tenham alta cardinalidade, o que significa muitos valores distintos e estatisticamente poucas linhas com o mesmo valor.
Tive o mesmo problema com o Maria DB 10.1.12, então após ler a documentação descobri que existe a opção de realizar a operação "in-place" que elimina a cópia da tabela. Com esta opção a alter table é muito rápida. No meu caso foi:
isso é muito rápido. Sem a opção de algoritmo, nunca terminaria.
https://mariadb.com/kb/en/mariadb/alter-table/
Para renomear a coluna,
deve estar bem e não levar qualquer tempo de inatividade.
Para os índices, a instrução CREATE INDEX bloqueará a tabela. Se for um escravo não utilizado como você mencionou, isso não é um problema.
Uma outra opção seria criar uma nova tabela que tenha os nomes e índices de coluna apropriados. Então você pode copiar todos os dados para ele, então executar uma série de
Isso minimizaria o tempo de inatividade ao custo de usar temporariamente o dobro do espaço.
Eu também tenho esse problema e usei este SQL:
Espero que possa ajudar alguém
Cumprimentos,
Vai