Uma maneira segura de acelerar um ALTER TABLE é remover índices desnecessários
Aqui estão as etapas iniciais para carregar uma nova versão da tabela
CREATE TABLE s_relations_new LIKE s_relations;
#
# Drop Duplicate Indexes
#
ALTER TABLE s_relations_new
DROP INDEX source_persona_index,
DROP INDEX target_persona_index,
DROP INDEX target_persona_relation_type_index
;
Por favor observe o seguinte:
Larguei source_persona_index porque é a primeira coluna em outros 4 índices
- unique_target_persona
- unique_target_object
- source_and_target_object_index
- source_target_persona_index
Larguei target_persona_index porque é a primeira coluna em outros 2 índices
- target_persona_relation_type_index
- target_persona_relation_type_message_id_index
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á o caminho para determinar isso:
Execute as seguintes consultas:
SELECT COUNT(DISTINCT sent_at) FROM s_relations;
SELECT COUNT(DISTINCT message_id) FROM s_relations;
SELECT COUNT(DISTINCT target_object_id) FROM s_relations;
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, isso seria 4.000.000.
- Se
COUNT(DISTINCT sent_at)
> 4.000.000
- então
ALTER TABLE s_relations_new
DROP INDEX sent_at_index;
- Se
COUNT(DISTINCT message_id)
> 4.000.000
- então
ALTER TABLE s_relations_new
DROP INDEX message_id_index;
- Se
COUNT(DISTINCT target_object_id)
> 4.000.000
- então
ALTER TABLE s_relations_new
DROP INDEX target_object_index;
Depois de determinar a utilidade ou inutilidade desses índices, você pode recarregar os dados
#
# Change the Column Name
# Load the Table
#
ALTER TABLE s_relations_new CHANGE sent_at sent_at_new int(11) DEFAULT NULL;
INSERT INTO s_relations_new SELECT * FROM s_relations;
É isso aí, né? NÃO !!!
Se o seu site estiver ativo o tempo todo, pode haver INSERTs sendo executados contra 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 em s_relations. Para garantir que a tabela esteja 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):
$ service mysql restart --skip-networking
Em seguida, efetue login no mysql e carregue as últimas linhas:
mysql> SELECT MAX(id) INTO @maxidnew FROM s_relations_new;
mysql> INSERT INTO s_relations_new SELECT * FROM s_relations WHERE id > @maxidnew;
mysql> ALTER TABLE s_relations RENAME s_relations_old;
mysql> ALTER TABLE s_relations_new RENAME s_relations;
Então, reinicie o mysql normalmente
$ service mysql restart
Agora, se você não pode derrubar o mysql, precisará fazer uma isca e alternar em s_relations. Apenas entre no mysql e faça o seguinte:
mysql> ALTER TABLE s_relations RENAME s_relations_old;
mysql> SELECT MAX(id) INTO @maxidnew FROM s_relations_new;
mysql> INSERT INTO s_relations_new SELECT * FROM s_relations_old WHERE id > @maxidnew;
mysql> ALTER TABLE s_relations_new RENAME s_relations;
De uma chance !!!
CAVEAT: Quando estiver satisfeito com esta operação, você poderá soltar a tabela antiga assim que possível:
mysql> DROP TABLE s_relations_old;
SHOW CREATE TABLE tblname\G
, mostre a coluna que precisa ser alterada, o tipo de dados da coluna e o novo nome para a coluna.