Eu tenho cerca de 40 milhões de linhas em uma tabela MySQL e quero copiar esta tabela para outra tabela no mesmo banco de dados. Qual é a maneira mais eficiente de fazer isso? Quanto tempo levará (aprox.)?
Eu tenho cerca de 40 milhões de linhas em uma tabela MySQL e quero copiar esta tabela para outra tabela no mesmo banco de dados. Qual é a maneira mais eficiente de fazer isso? Quanto tempo levará (aprox.)?
Respostas:
Suponha que você tenha mydb.mytb
e queira criarmydb.mytbcopy
Eu tenho cinco (5) abordagens para fazer esta cópia
No mysql
cliente, execute o seguinte
USE mydb
CREATE TABLE mytbcopy LIKE mytb;
INSERT INTO mytbcopy SELECT * FROM mytb;
MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
mysql ${MYSQL_CONN} -ANe"CREATE DATABASE IF NOT EXISTS test"
mysqldump ${MYSQL_CONN} mydb mytb | mysql ${MYSQL_CONN} -Dtest
mysql ${MYSQL_CONN} -ANe"ALTER TABLE test.mytb RENAME mydb.mytbcopy"
DUMPFILE=/some/path/tabledata.sql
MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
mysql ${MYSQL_CONN} -ANe"CREATE DATABASE IF NOT EXISTS test"
mysqldump ${MYSQL_CONN} mydb mytb > ${DUMPFILE}
mysql ${MYSQL_CONN} -Dtest < ${DUMPFILE}
rm -f ${DUMPFILE}
mysql ${MYSQL_CONN} -ANe"ALTER TABLE test.mytb RENAME mydb.mytbcopy"
MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
mysqldump ${MYSQL_CONN} mydb mytb | sed 's/mytb/mytbcopy' | mysql ${MYSQL_CONN} -Dmydb
DUMPFILE=/some/path/tabledata.sql
MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
mysqldump ${MYSQL_CONN} mydb mytb | sed 's/mytb/mytbcopy' > ${DUMPFILE}
mysql ${MYSQL_CONN} -Dmydb < ${DUMPFILE}
rm -f ${DUMPFILE}
Se você deseja copiar mydb.mytb
para uma tabela já existente mydb.mytbcopy
, e as duas tabelas possuem estruturas idênticas:
INSERT INTO mytbcopy SELECT * FROM mytb;
Assim como o #APPROACH 1 , o #APPROACH 6 teria uma única transação de 40 milhões de linhas
MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
mysqldump ${MYSQL_CONN} -t mydb mytb | sed 's/mytb/mytbcopy' | mysql ${MYSQL_CONN} -Dmydb
Essa abordagem não descarta a tabela. Simplesmente gera os INSERTs
Não posso fornecer uma estimativa de tempo, pois não conheço a composição do DB Server, a estrutura da tabela, o layout do índice e coisas assim.
As tabelas do InnoDB, diferentemente do MyISAM *, não podem ser "simplesmente copiadas", como parte de seu dicionário de dados (e potencialmente outras estruturas em que a tabela depende, como o buffer de mesclagem) estão localizadas na memória (se o servidor estiver em execução) e em o espaço de tabela comum / principal, também conhecido como arquivo grande chamado ibdata1
.
Se você estiver usando o Percona Server> = 5.1 ou MySQL> = 5.6, há suporte para espaços de tabela transportáveis, o que permite exportar e importar tabelas diretamente do sistema de arquivos. Aqui está o método para MySQL e Percona . Nos dois casos, é necessário que você tenha criado a tabela com a innodb_file_per_table
opção e envolva o uso de DISCARD TABLESPACE/IMPORT TABLESPACE
e / ou Percona Xtrabakup (se desejar que a exportação seja feita on-line). Observe que o Percona Server ou o Xtrabakup não estão disponíveis para Windows.
Este método será, falando em geral, tão rápido quanto copiar o arquivo usando os comandos do sistema de arquivos (cp, rsync).
Embora possa haver alguns casos em que isso possa funcionar no MySQL <5.6 (de maneira hacky) para restaurações, ele não funcionará para uma cópia da tabela. Nesses casos, uma maneira de fazer isso é usando o SQL :
CREATE TABLE new_table LIKE old_table;
INSERT INTO new_table SELECT * FROM old_table;
Isso será o mais rápido que o InnoDB pode executar Handler_read_rnd_next
e Handler_write
, uma vez por linha. Se você usar esse método, desabilite, pelo menos temporariamente, as opções de durabilidade e tenha um grande buffer pool e log de transações. Nessas circunstâncias, pode reduzir o tempo de importação, mas definitivamente não caberá totalmente na memória; portanto, espere muito tempo. Além disso, você está tentando importar linhas de 40 milhões em uma única transação, o que pode levar a problemas.
Minha recomendação real, neste segundo caso, seria usar algo como pt-archiver , pois ele executará uma operação semelhante à que acabei de mencionar, mas será feita em "pedaços", evitando a sobrecarga transacional (pode ser não seja mais rápido, mas, no caso de uma falha, ele não tentará reverter a tabela inteira, levando uma eternidade). Para os tamanhos de dados mencionados, este é provavelmente o melhor caminho a percorrer.
Uma opção final seria exportar e importar usando o formato CSV (ou TSV) , com uma combinação de SELECT INTO OUTFILE / mysqldump e LOAD DATA / mysqlimport. Essa era uma opção muito comum se você precisasse de simultaneidade em certas versões antigas do mysql, pois o sql criava bloqueios maiores (não é mais verdade se feito corretamente). Como o mysqldump / import funciona apenas de maneira serializada, eu recomendaria que você pesquisasse opções para paralelizar isso, muito útil para tabelas grandes.
De qualquer forma, tente evitar várias frases SQL, pois será o seu gargalo mais importante se você executar muitas consultas diferentes (que precisam ser executadas, analisadas e otimizadas individualmente).
* As estruturas MyISAM não podem ser copiadas de maneira quente, mas é muito fácil sincronizá-las temporariamente com o disco FTWRL
.
mover dados de uma tabela para outra no esquema
create table your_table_name select * from old_schema_table;