Como adicionar uma coluna à tabela grande no MySQL

12

Eu sou desenvolvedor de PHP, então não seja rigoroso. Eu tenho uma grande mesa ~ despejo 5.5gb. Nosso PM decidiu criar uma nova coluna para executar um novo recurso. Tabela é InnoDB então o que eu tentei:

  1. Altere a tabela na tela com o bloqueio da tabela. Tomou ~ 30 horas e nada. Então eu apenas parei. Primeiro cometi um erro porque não encerrei todas as transações, mas a 2ª vez não foi multitoque. O status era copy to tmp table.

  2. Como também preciso aplicar o particionamento para esta tabela, decidimos fazer dump, renomear e criar tabela com o mesmo nome e nova estrutura. Mas o dump está fazendo uma cópia estrita (pelo menos eu não encontrei outra coisa). Então eu adicionei para despejar uma nova coluna sede consultá-la. Mas alguns erros estranhos começaram. Eu acredito que foi causado por charset. A tabela no utf-8 e o arquivo se tornaram us-ascii depois sed. Então, eu tenho erros (comando desconhecido '\' ') em 30% dos dados. Portanto, este também é um caminho ruim.

Quais são as outras opções para conseguir isso e acelerar o desempenho (eu posso fazer isso com o script php, mas levará séculos). Qual será o desempenho INSERT SELECTnesse caso.

Obrigado por qualquer avanço.

ineersa
fonte

Respostas:

11

Use o MySQL Workbench . Você pode clicar com o botão direito do mouse em uma tabela e selecionar "Enviar para o SQL Editor" -> "Criar instrução". Dessa forma, nenhuma tabela "propriedades" será esquecida de adicionar (incluindo CHARSETou COLLATE).
Com essa enorme quantidade de dados, eu recomendaria limpar a tabela ou a estrutura de dados que você usa (um bom DBA é útil). Se não for possível:

  • renomeie a tabela ( ALTER) e crie uma nova com o CREATEscript obtido do Workbench. Você também pode estender essa consulta com o novo campo necessário
  • CARREGUE em massa os dados da tabela antiga para a nova:
    SET FOREIGN_KEY_CHECKS = 0;
    SET UNIQUE_CHECKS = 0;
    SET AUTOCOMMIT = 0;
    INSERT INTO new_table (fieldA, fieldB, fieldC, ..., fieldN)
       SELECT fieldA, fieldB, fieldC, ..., fieldN
       FROM old_table
    SET UNIQUE_CHECKS = 1;
    SET FOREIGN_KEY_CHECKS = 1;
    COMMIT;

    Dessa forma, você evita indexar / etc para executar registro por registro. A "atualização" da tabela ainda será lenta (já que a quantidade de dados é enorme), mas é a maneira mais rápida que consigo pensar.

    EDIT: Leia este artigo para obter detalhes sobre os comandos usados ​​na consulta de exemplo acima;)

fonte
Minhas opções estão bem. E eu tenho SET NAMES utf8e COLLATION.But meh idk porque 30% dos dados corrompidos depois sed. Eu acho que a carga em massa será a mais rápida, mas talvez exista algo mais do que estou perdendo. Obrigado, Mark
ineersa
1
A corrupção de dados do @ineersa pode ter muitos motivos: por exemplo, você abriu o arquivo com um editor que não suporta todos os caracteres e o salvou. Ou, a maneira como você tenta importar do dump corrompe os dados (é incorreto e não consegue ler o arquivo corretamente). Ou, o mesmo cara pode identificar parte de alguns dados como uma expressão (por exemplo, "james \ robin" == "\ r" como expressão) ou comando, etc. É por isso que eu nunca recomendo usar o dump, nem mesmo com a ferramenta de despejo de dados binários somente, nem mesmo com dev.mysql.com/doc/refman/5.6/en/mysqldump.html (ou BCP para MS SQL Server). Ele dá errado muitas vezes ...
sim eu tentei com hex-blob. isso não ajuda. Além disso, você logo após usar o sed mysql identifica \ 'como comando em alguns nomes (não em todos). Isso é estranho e com bugs. Tentará carga em massa hoje à noite. Espero que seja feito pelo menos em 10-15 horas.
ineersa
@ineersa espero que sim. você também pode tentar adicionar apenas parte dos dados, digamos 10% para ver quanto tempo leva - e ter uma estimativa para toda a transação. Será uma estimativa muito grosseira, porém, as coisas podem ficar lentas se caches / memória / o que for preenchido / sobrecarregado.
1
Obrigado Mark. Trabalhou incrível. Ainda mais rápido do que restaurar do despejo. Levou ~ 5 horas.
precisa saber é
5

Sua ideia sed é um método decente, mas sem os erros ou o comando que você executou, não podemos ajudá-lo.

No entanto, um método bem conhecido para fazer alterações online em tabelas grandes é pt-online-schema-change . A negligência simplista do que essa ferramenta faz é copiada da documentação:

pt-online-schema-change funciona criando uma cópia vazia da tabela para alterar, modificando-a conforme desejado e, em seguida, copiando linhas da tabela original para a nova tabela. Quando a cópia é concluída, ela afasta a tabela original e a substitui pela nova. Por padrão, ele também descarta a tabela original.

Esse método também pode demorar um pouco para ser concluído, mas durante o processo a tabela original será completamente utilizável.

Derek Downey
fonte
Vou tentar o carregamento em massa mais tarde hoje à noite. Se não funcionar, provavelmente precisará dessa ferramenta. Os erros são causados ​​por inetifiengeng alguns símbolos depois de usar sed como comandos. Por exemplo 'D\'agostini', causará erro unknown command '\''. Mas nem sempre, como em 30% dos casos. Isso é estranho e com bugs. O mesmo acontece com os dumps hexadecimais. Obrigado Derek.
ineersa
4

alter table add column, algorithm=inplace, lock=none irá alterar uma tabela do MySQL 5.6 sem copiar a tabela e sem travar o impacto.

Acabei de testar isso ontem, massa inserida 70K linhas em uma tabela de partição de 280K 7 linhas, 10K linhas em cada partição, com 5 segundos de sono entre eles para permitir outra taxa de transferência.

Iniciou as inserções em massa e, em sessão separada, iniciou a alterinstrução on-line acima no MySQL Workbench, alterfinalizada antes das inserções, duas novas colunas foram adicionadas e nenhuma linha resultou da alteração, o que significa que o MySQL não copiou nenhuma linha.

SAK
fonte
1
Por que esta resposta não está recebendo mais votos ?, não está funcionando?
fguillen
1

Atualmente, a melhor opção para alterar tabelas enormes é provavelmente https://github.com/github/gh-ost

O gh-ost é uma solução de migração de esquema on-line sem gatilho para o MySQL. É testável e oferece capacidade de pausa, controle / reconfiguração dinâmica, auditoria e muitas vantagens operacionais.

O gh-ost produz uma carga de trabalho leve no mestre durante toda a migração, desacoplado da carga de trabalho existente na tabela migrada.

Ele foi projetado com base em anos de experiência com soluções existentes e altera o paradigma das migrações de tabelas.

iJanki
fonte
1

Eu acho que o Mydumper / Myloader é uma boa ferramenta para operações como esta: está melhorando a cada dia. Você pode utilizar suas CPUs e carregar dados em paralelo: http://www.percona.com/blog/2014/03/10/new-mydumper-0-6-1-release-offers-several-performance-and- recursos de usabilidade /

Consegui carregar centenas de gigabytes de tabelas MySQL em horas.

Agora, quando se trata de adicionar uma nova coluna, é complicado, pois o MySQL copia toda a tabela para a TMPárea de memória com ALTER TABLE...Embora o MySQL 5.6 diga que pode fazer alterações de esquema on-line, eu não consegui fazê-las on-line para tabelas maciças sem bloqueio contenção ainda.

Kubilay
fonte
-2

Eu apenas tive o mesmo problema. Um pouco de solução alternativa:

CREATE TABLE new_table SELECT * FROM tabela antiga;

DELETE FROM new_table

ALTER TABLE new_table ADD COLUMN new_column int (11);

INSERIR EM nova_tabela selecione *, 0 de antiga_tabela

soltar tabela old_table; renomeie a tabela new_table para old_table;

AirCoder
fonte
Por que não adicionar uma cláusula where à instrução create table para que ela não selecione nenhum dado? Também truncando a tabela seria mais eficiente, em seguida, a eliminação dos dados
Joe W
por que excluir, quando tem que inserir mais tarde, novamente. Pode definir o padrão = 0 no próprio ADD COLUMN.
user195280