baixa velocidade de carregamento de dados do mysqldump

21

Eu tenho um banco de dados MySQL de tamanho moderado com cerca de 30 tabelas, algumas das quais 10 milhões de registros, outras 100 milhões. O mysqldumpde todas as tabelas (em arquivos separados) é bastante rápido, leva talvez 20 minutos. Ele gera cerca de 15 GB de dados. Os maiores arquivos despejados estão na faixa de 2 GB.

Quando carrego os dados no MySQL em outra caixa, uma máquina de 8 GB e seis núcleos, leva uma eternidade. Facilmente 12 horas de relógio ou mais.

Estou apenas executando o cliente mysql para carregar o arquivo, ou seja,

mysql database < footable.sql

diretamente com o arquivo diretamente do mysqldump

mysqldump database foo > footable.sql

Claramente, estou fazendo algo errado. Por onde começo para que possa terminar em um tempo razoável?

Não estou usando nenhuma opção no despejo ou na carga.

Pat Farrell
fonte
Você também pode desativar o log binário durante o carregamento do seu dump.
Cédric PEINTRE

Respostas:

22

Considere esses pontos em consideração: eles podem ajudá-lo no caso de gerar o despejo e restaurá-lo.

  1. Use Extended insertsem lixões.
  2. Despejar com --tabformato para que você possa usar mysqlimport, o que é mais rápido que mysql < dumpfile.
  3. Importe com vários threads, um para cada tabela.
  4. Use um mecanismo de banco de dados diferente, se possível. importar para um mecanismo altamente transacional como o innodb é muito lento. A inserção em um mecanismo não transacional como o MyISAM é muito mais rápido.
  5. Desative as verificações de chave estrangeira e ative a confirmação automática.
  6. Se você estiver importando para o innodb, a coisa mais eficaz que você pode fazer é colocar innodb_flush_log_at_trx_commit = 2no my.cnf temporariamente enquanto a importação está em execução. você pode voltar para 1 se precisar de ACID

De uma chance..

Abdul Manaf
fonte
Sua dica innodb_flush_log_at_trx_commit = 2salvou meu dia. A importação de um despejo de 600 MB (como uma única transação grande) levaria 6 horas, mas com essa configuração temporária, isso foi feito em 30 minutos!
Daniel Marschall
1
As coisas que você gostaria de saber antes de tentar carregar um banco de dados 80gig de um despejo 4 dias após pressionar 'enter' ... :) #
Dmitri DB
7

Além da resposta de Abdul , gostaria de enfatizar a importância da --disable-keysopção, que desativa as teclas até que todos os dados sejam carregados para uma tabela. Esta opção está ativada como parte da --optalternância, que é ativada por padrão, mas considerou importante ressaltar.

Se você não pular chaves durante as inserções, cada linha inserida reconstruirá o índice. Um processo extremamente lento.

Derek Downey
fonte
é --disable-keys parte do mysqldump? ou a recarga?
22812 Pat Patton Farrell
ele será adicionado no arquivo de despejo
Derek Downey
--optestá
ativado
1
This option is effective only for nonunique indexes of MyISAM tables. It has no effect for other tables
Ethan Allen
7

Ultimamente tenho lidado muito com isso. Você pode definitivamente melhorar o desempenho da importação, realizando as importações em paralelo. A maior parte da desaceleração é baseada em E / S, mas você ainda pode obter uma melhoria de 40% despejando tabelas e importando-as, digamos, 4 por vez.

Você pode fazer isso com xargs assim:

ls *.sql -1c | xargs -P4 -I tbl_name sh -c "mysql --user=username --password database < tbl_name"

ter os arquivos compactados antes de enviá-los para o mysql não diminui nada principalmente por causa da E / S reduzida. Minhas tabelas foram compactadas em até 10: 1, economizando muito espaço em disco.

Descobri que em 4 máquinas principais, o uso de 4 processos é ideal, embora apenas marginalmente melhor do que o uso 3. Se você tiver SSDs ou um RAID rápido, provavelmente escalará melhor.

Algumas outras coisas a serem observadas. Se você possui unidades do setor de 4k, verifique se possui key_cache_block_size=4096e myisam_block_size=4K.

Se você estiver usando tabelas MyISAM, defina o myisam_repair_threads = 2ou superior. Isso permitirá que seus núcleos extras ajudem a reconstruir índices.

Verifique se você não está trocando nada. Se estiver, reduza o tamanho do innodb_buffer_pool_size.

Eu acho que consegui um pouco de aceleração com o innnodb por essas opções também:

innodb_flush_method= O_DIRECT (LINUX ONLY)
innodb_flush_log_at_commit = 0
innodb_doublewrite=0
innodb_support_xa=0
innodb_checksums=0

(os três últimos que não testei extensivamente - acho que os encontrei como sugestões nos internets.) Observe que isso innodb_flush_log_at_commit=0pode resultar em corrupção com o travamento do mysql ou com a falta de energia.

greg
fonte
Greg, seja bem-vindo ao site e obrigado por sua resposta. Você poderia fornecer algumas fontes ou justificativas para suas sugestões *_block_sizee myisam_repair_threads? Além disso, não temos certeza se devemos oferecer conselhos para ajustar as variáveis ​​com base nas 'sugestões dos internets' :) #
687 Derek Downey
5

Se você possui principalmente tabelas MyISAM, deve aumentar o buffer de inserção em massa . Aqui está o que a documentação do MySQL diz sobre a configuração bulk_insert_buffer_size :

O MyISAM usa um cache especial em forma de árvore para tornar as inserções em massa mais rápidas para INSERT ... SELECT, INSERT ... VALUES (...), (...), ... e LOAD DATA INFILE ao adicionar dados a objetos não vazios mesas. Essa variável limita o tamanho da árvore de cache em bytes por encadeamento. Definir como 0 desativa essa otimização. O valor padrão é 8 MB.

Há duas coisas que você precisa fazer

1) Adicione-o ao /etc/my.cnf

[mysqld]
bulk_insert_buffer_size=512M

2) Defina o valor global para ele

SET GLOBAL bulk_insert_buffer_size = 1024 * 1024 * 512;

Se você não tiver o privilégio de definir globalmente bulk_insert_buffer_size, faça isso

service mysql restart

Obviamente, isso não é para o InnoDB.

De outro ângulo, se as tabelas são InnoDB ou MyISAM, se os índices forem maiores que a tabela, você poderá ter muitos índices. Eu costumo prever que uma recarga de um mysqldump do MyISAM deve levar três vezes o tempo que o mysqldump demorou para ser feito. Também acredito que a recarga de um mysqldump do InnoDB deve levar 4 vezes o tempo que o mysqldump demorou para ser feito.

Se você está excedendo a proporção de 4: 1 para recarregar um mysqldump, você definitivamente tem um dos dois problemas:

  • muitos índices
  • índices muito grandes devido a colunas grandes

Você pode medir o tamanho dos seus dados pelo mecanismo de armazenamento com este:

SELECT IFNULL(B.engine,'Total') "Storage Engine",
CONCAT(LPAD(REPLACE(FORMAT(B.DSize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Data Size", CONCAT(LPAD(REPLACE(
FORMAT(B.ISize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Index Size", CONCAT(LPAD(REPLACE(
FORMAT(B.TSize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Table Size" FROM
(SELECT engine,SUM(data_length) DSize,SUM(index_length) ISize,
SUM(data_length+index_length) TSize FROM
information_schema.tables WHERE table_schema NOT IN
('mysql','information_schema','performance_schema') AND
engine IS NOT NULL GROUP BY engine WITH ROLLUP) B,
(SELECT 3 pw) A ORDER BY TSize;

Veja se os índices são quase tão grandes quanto os dados ou até maiores

Você também pode desabilitar o log binário como este:

echo "SET SQL_LOG_BIN=0;" > footable.sql
mysqldump --databases foo >> footable.sql

antes de recarregar o script

RolandoMySQLDBA
fonte
Eu não sei quantas vezes você salvou o meu dia, mas com certeza tem sido um monte
Dmitri DB
2

Se você ignorar completamente o sistema de arquivos e apenas canalizar a saída do mysqldump diretamente para um processo MySQL, deverá ver melhorias visíveis no desempenho. Em última análise, quanto depende do tipo de unidade de disco que você está usando, mas raramente uso mais arquivos de despejo, independentemente do tamanho do banco de dados, apenas por esse motivo.

mysqldump -uxxx -pxxx -hxxx --single-transaction --routines --databases dbname | mysql -uyyy -pyyy -hyyy
Marcus Pope
fonte
1

De acordo com minhas experiências, o disco rígido é o gargalo. Esqueça os discos giratórios. O SSD é melhor, mas de longe o melhor é fazer isso na RAM - se você tiver o suficiente para armazenar todo o banco de dados por um curto período de tempo. Aproximadamente:

  1. pare o mysqld
  2. afastar o conteúdo existente de / var / lib / mysql
  3. crie um diretório / var / lib / mysql vazio
  4. mount -t tmpfs -o size = 32g tmpfs / var / lib / mysql (ajuste o tamanho)
  5. crie um banco de dados vazio (por exemplo, mysql_install_db ou restaure o conteúdo anterior)
  6. inicie o mysqld
  7. importar
  8. pare o mysqld
  9. copie / var / lib / mysql para mysql2
  10. um pouco de mysql; rmdir mysql
  11. mova mysql2 para mysql
  12. inicie o mysqld, seja feliz

Para mim, um dump de ~ 10G (/ var / lib / mysql consome ~ 20G) pode ser importado em cerca de 35 minutos (mydumper / myloader), 45 minutos (mysqldump --tab / mysqlimport), 50 minutos (mysqldump / mysql) , em um Xeon de 3,2 GHz e 2x6 núcleos.

Se você não tiver RAM suficiente em uma única máquina, mas tiver vários computadores próximos um do outro com rede rápida, seria interessante verificar se as RAMs deles podem ser unidas ao nbd (dispositivo de bloco de rede). Ou, com innodb_file_per_table, você provavelmente pode repetir o processo acima para cada tabela.

Egmont
fonte
Por curiosidade, tentei armazenar o datadir mysql na RAM para compará-lo com um SSD (SSDSC2BB48 para os interessados) para um banco de dados de 2 GB. Os resultados foram idênticos, ambos levaram 207-209 segundos. Considerando o fato de que você também tem que iniciar / parar mysql e copiar os diretórios, usando um disco de RAM em vez do SSD foi muito mais lento no meu caso
Shocker
Se você levou de 3 a 4 minutos, acho que você tem um banco de dados significativamente menor do que o tópico. Seria interessante ouvir sobre suas experiências com bancos de dados igualmente grandes do que os mencionados neste tópico.
Egmont