Tengo alrededor de 40 millones de filas en una tabla MySQL y quiero copiar esta tabla en otra tabla en la misma base de datos. ¿Cuál es la forma más eficiente de hacer esto? ¿Cuánto tiempo llevará (aprox.)?
Tengo alrededor de 40 millones de filas en una tabla MySQL y quiero copiar esta tabla en otra tabla en la misma base de datos. ¿Cuál es la forma más eficiente de hacer esto? ¿Cuánto tiempo llevará (aprox.)?
Respuestas:
Supongamos que tienes mydb.mytb
y quieres crearmydb.mytbcopy
Tengo cinco (5) enfoques para hacer esta copia
En el mysql
cliente, ejecute lo siguiente
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 desea copiar mydb.mytb
en una tabla ya existente mydb.mytbcopy
, y las dos tablas tienen estructuras idénticas:
INSERT INTO mytbcopy SELECT * FROM mytb;
Al igual que #APPROACH 1 , #APPROACH 6 tendría una sola transacción de 40 millones de filas
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
Este enfoque no deja caer la tabla. Simplemente genera los INSERTOS
No puedo darle una estimación de tiempo, ya que no conozco la composición del servidor DB, la estructura de la tabla, el diseño del índice y cosas como estas.
Las tablas InnoDB, a diferencia de MyISAM *, no pueden "copiarse", como parte de su diccionario de datos (y potencialmente otras estructuras de las que depende la tabla, como el búfer de fusión) se encuentran en la memoria (si el servidor está funcionando) y en el espacio de tabla común / principal, también conocido como ese archivo grande llamado ibdata1
.
Si está utilizando Percona Server> = 5.1 o MySQL> = 5.6, hay soporte para espacios de tablas transportables, lo que le permite exportar e importar tablas directamente desde el sistema de archivos. Aquí está el método para MySQL y para Percona . En ambos casos, se requiere que haya creado la tabla con la innodb_file_per_table
opción e implica el uso de DISCARD TABLESPACE/IMPORT TABLESPACE
y / o Percona Xtrabakup (si desea que la exportación se realice en línea). Tenga en cuenta que Percona Server o Xtrabakup no están disponibles para Windows.
Este método será, hablando en general, tan rápido como copiar el archivo usando los comandos del sistema de archivos (cp, rsync).
Si bien puede haber algunos casos en que esto podría funcionar en MySQL <5.6 (de una manera hacky) para las restauraciones, no funcionará para una copia de la tabla. En esos casos, una forma de hacerlo es usando SQL :
CREATE TABLE new_table LIKE old_table;
INSERT INTO new_table SELECT * FROM old_table;
Esto será tan rápido como InnoDB puede ejecutar Handler_read_rnd_next
y Handler_write
, una vez por fila. Si usa este método, asegúrese de deshabilitar, al menos temporalmente, las opciones de durabilidad y de tener un gran grupo de búferes y un registro de transacciones. En esas circunstancias, puede reducir el tiempo de importación, pero definitivamente no cabe en la memoria por completo, así que espere mucho tiempo. Además, está intentando importar 40 millones de filas en una sola transacción, lo que puede generar problemas.
Mi recomendación real, en este segundo caso, sería usar algo como pt-archiver , ya que realizará una operación similar a la que acabo de mencionar, pero se realizará en "fragmentos", evitando la sobrecarga transaccional (puede no será más rápido, pero en caso de falla, no intentará deshacer toda la tabla, demorando para siempre). Para los tamaños de datos que menciona, esta es probablemente la mejor manera de hacerlo.
Una opción final sería exportar e importar utilizando el formato CSV (o TSV) , con una combinación de SELECCIONAR EN SALIDA / mysqldump y CARGAR DATOS / mysqlimport. Esta era una opción muy común si necesitaba concurrencia en ciertas versiones antiguas de mysql, ya que el uso de sql creó bloqueos más grandes (ya no es cierto si se hace correctamente). Como mysqldump / import solo funciona de forma serializada, te recomendaría investigar opciones para paralelizarlo, muy útil para tablas grandes.
En cualquier caso, trate de evitar múltiples oraciones SQL, ya que será su cuello de botella más importante si ejecuta muchas consultas diferentes (que deben ejecutarse, analizarse y optimizarse individualmente).
* Las estructuras MyISAM no se pueden copiar de manera activa, pero es muy fácil sincronizarlas temporalmente en el disco FTWRL
.
mover datos de una tabla a otra en esquema
create table your_table_name select * from old_schema_table;