Ho circa 40 milioni di righe in una tabella MySQL e voglio copiare questa tabella in un'altra tabella nello stesso database. Qual è il modo più efficace per farlo? Quanto tempo ci vorrà (circa)?
Ho circa 40 milioni di righe in una tabella MySQL e voglio copiare questa tabella in un'altra tabella nello stesso database. Qual è il modo più efficace per farlo? Quanto tempo ci vorrà (circa)?
Risposte:
Supponiamo di avere mydb.mytb
e di voler crearemydb.mytbcopy
Ho cinque (5) approcci per fare questa copia
Nel mysql
client, eseguire quanto segue
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 si desidera copiare mydb.mytb
in una tabella già esistente mydb.mytbcopy
e le due tabelle hanno strutture identiche:
INSERT INTO mytbcopy SELECT * FROM mytb;
Come #APPROACH 1 , #APPROACH 6 avrebbe un'unica transazione di 40 milioni di righe
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
Questo approccio non elimina la tabella. Genera semplicemente gli INSERTI
Non posso darti una stima del tempo poiché non conosco la composizione del DB Server, la struttura della tabella, il layout dell'indice e cose come queste.
Le tabelle InnoDB, diversamente da MyISAM *, non possono essere "semplicemente copiate", poiché parte del suo dizionario di dati (e potenzialmente altre strutture da cui dipende la tabella, come il buffer di unione) si trovano in memoria (se il server è in esecuzione) e in il tablespace comune / principale, noto anche come file di grandi dimensioni chiamato ibdata1
.
Se si utilizza Percona Server> = 5.1 o MySQL> = 5.6, esiste il supporto per tablespace trasportabili, che consente di esportare e importare le tabelle direttamente dal filesystem. Ecco il metodo per MySQL e Percona . In entrambi i casi, è necessario aver creato la tabella con l' innodb_file_per_table
opzione e prevede l'utilizzo di DISCARD TABLESPACE/IMPORT TABLESPACE
e / o Percona Xtrabakup (se si desidera che l'esportazione venga eseguita online). Si noti che Percona Server o Xtrabakup non sono disponibili per Windows.
Questo metodo sarà, parlando in generale, veloce come copiare il file usando i comandi del filesystem (cp, rsync).
Sebbene in alcuni casi ciò possa funzionare in MySQL <5.6 (in modo confuso) per i ripristini, non funzionerà per una copia della tabella. In questi casi, un modo per farlo è utilizzare SQL :
CREATE TABLE new_table LIKE old_table;
INSERT INTO new_table SELECT * FROM old_table;
Sarà veloce quanto InnoDB può eseguire Handler_read_rnd_next
e Handler_write
, una volta per riga. Se si utilizza questo metodo, assicurarsi di disabilitare, almeno temporaneamente, le opzioni di durabilità e di disporre di un pool buffer e di un registro delle transazioni di grandi dimensioni. In tali circostanze, potrebbe ridurre i tempi di importazione, ma sicuramente non si adatterà completamente alla memoria, quindi aspettati molto tempo. Inoltre, stai tentando di importare 40 milioni di righe in una singola transazione, il che potrebbe causare problemi.
La mia attuale raccomandazione, in questo secondo caso, sarebbe quella di utilizzare qualcosa come l' archiviatore pt , in quanto eseguirà un'operazione simile a quella che ho appena menzionato, ma verrà eseguita in "blocchi", evitando il sovraccarico transazionale (potrebbe non essere più veloce, ma in caso di errore, non tenterà di ripristinare l'intero tavolo, impiegando un'eternità). Per le dimensioni dei dati menzionate, questo è probabilmente il modo migliore per procedere.
Un'ultima opzione sarebbe quella di esportare e importare usando il formato CSV (o TSV) , con una combinazione di SELECT INTO OUTFILE / mysqldump e LOAD DATA / mysqlimport. Questa era un'opzione molto comune se avevi bisogno di concorrenza in alcune vecchie versioni di mysql, poiché l'uso di sql creava blocchi più grandi (non più vero se fatto correttamente). Dato che mysqldump / import funziona solo in modo serializzato, ti consiglierei di cercare opzioni per parallelizzarlo, molto utile per tabelle di grandi dimensioni.
In ogni caso, cerca di evitare più frasi SQL, poiché sarà il tuo collo di bottiglia più importante se esegui molte query diverse (che devono essere eseguite, analizzate e ottimizzate individualmente).
* Le strutture MyISAM non possono essere copiate a caldo, ma è molto facile sincronizzarle temporaneamente con il disco FTWRL
.
spostare i dati da una tabella all'altra nello schema
create table your_table_name select * from old_schema_table;