J'ai environ 40 millions de lignes dans une table MySQL et je veux copier cette table dans une autre table de la même base de données. Quelle est la manière la plus efficace de procéder? Combien de temps cela prendra-t-il (environ)?
Supposons que vous ayez mydb.mytb
et vous voulez créer mydb.mytbcopy
J'ai cinq (5) approches pour faire cette copie
Dans le client mysql
, exécutez ce qui suit
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}
Si vous souhaitez copier mydb.mytb
vers une table déjà existante mydb.mytbcopy
, et les deux tables ont des structures identiques:
INSERT INTO mytbcopy SELECT * FROM mytb;
Comme # APPROCHE 1 , # APPROCHE 6 aurait une seule transaction de 40 millions de lignes
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
Cette approche ne laisse pas tomber le tableau. Il génère simplement les INSERT
Je ne peux pas vous donner d'estimation de temps car je ne connais pas la composition du serveur DB, la structure de la table, la disposition des index et des choses comme celles-ci.
Les tables InnoDB, contrairement à MyISAM *, ne peuvent pas être "simplement copiées", car une partie de son dictionnaire de données (et potentiellement d'autres structures dont la table dépend, comme le tampon de fusion) sont situées en mémoire (si le serveur est en cours d'exécution) et dans l'espace de table commun/principal, alias ce gros fichier appelé ibdata1
.
Si vous utilisez Percona Server> = 5.1 ou MySQL> = 5.6, les espaces de table transportables sont pris en charge, ce qui vous permet d'exporter et d'importer des tableaux directement à partir du système de fichiers. Voici la méthode pour MySQL et pour Percona . Dans les deux cas, vous devez avoir créé la table avec le innodb_file_per_table
option et implique l'utilisation de DISCARD TABLESPACE/IMPORT TABLESPACE
et/ou Percona Xtrabakup (si vous souhaitez que l'exportation se fasse en ligne). Veuillez noter que Percona Server ou Xtrabakup ne sont pas disponibles pour Windows.
Cette méthode sera, parlant en général, aussi rapide que la copie du fichier en utilisant les commandes du système de fichiers (cp, rsync).
Bien qu'il puisse y avoir des cas où cela pourrait fonctionner dans MySQL <5.6 (de manière hacky) pour les restaurations, cela ne fonctionnera pas pour une copie de table. Dans ces cas, une façon de le faire est d'utiliser SQL :
CREATE TABLE new_table LIKE old_table;
INSERT INTO new_table SELECT * FROM old_table;
Ce sera aussi rapide que InnoDB peut exécuter Handler_read_rnd_next
et Handler_write
, une fois par ligne. Si vous utilisez cette méthode, assurez-vous que vous désactivez, au moins temporairement, les options de durabilité et que vous disposez d'un grand pool de mémoire tampon et d'un journal des transactions. Dans ces circonstances, cela peut réduire le temps d'importation, mais il ne rentrera certainement pas dans la mémoire, alors attendez-vous beaucoup de temps. En outre, vous essayez d'importer 40 millions de lignes en une seule transaction, ce qui peut entraîner des problèmes.
Ma recommandation réelle, dans ce deuxième cas, serait d'utiliser quelque chose comme pt-archiver, car il effectuera une opération similaire à celui que je viens de mentionner, mais cela se fera en "morceaux", en évitant les frais généraux transactionnels (ce ne sera peut-être pas plus rapide, mais en cas d'échec, il n'essaiera pas de faire reculer toute la table, prenant une éternité ). Pour les tailles de données que vous mentionnez, c'est probablement la meilleure façon de procéder.
Une dernière option serait d'exporter et d'importer en utilisant le format CSV (ou TSV) , avec une combinaison de SELECT INTO OUTFILE/mysqldump et LOAD DATA/mysqlimport . C'était une option très courante si vous aviez besoin de l'accès simultané dans certaines anciennes versions de mysql, car l'utilisation de sql créait de plus grands verrous (ce n'est plus vrai si cela est fait correctement). Comme mysqldump/import ne fonctionne que de manière sérialisée, je vous recommande de rechercher des options pour le paralléliser, très utile pour les grandes tables.
Dans tous les cas, essayez d'éviter plusieurs phrases SQL, car ce sera votre goulot d'étranglement le plus important si vous exécutez de nombreuses requêtes différentes (qui doivent être exécutées, analysées et optimisées individuellement).
* Les structures MyISAM ne peuvent pas être copiées à chaud, mais il est très facile de les synchroniser temporairement sur le disque avec FTWRL
.
déplacer des données d'une table à une autre dans le schéma
create table your_table_name select * from old_schema_table;