velocidad de carga lenta de datos de mysqldump

21

Tengo una base de datos MySQL de tamaño moderado con aproximadamente 30 tablas, algunas de las cuales son 10 millones de registros, algunas de 100 millones. La mysqldumpmayoría de las tablas (en archivos separados) es bastante rápida, lleva unos 20 minutos. Genera unos 15 GB de datos. Los archivos volcados más grandes están en el rango de 2GB.

Cuando cargo los datos en MySQL en otra caja, una máquina de seis núcleos y 8 GB, me lleva una eternidad. Fácilmente 12 horas de reloj o más.

Solo estoy ejecutando el cliente mysql para cargar el archivo, es decir

mysql database < footable.sql

directamente con el archivo directamente de mysqldump

mysqldump database foo > footable.sql

Claramente estoy haciendo algo mal. ¿Dónde empiezo para que pueda terminar en un tiempo razonable?

No estoy usando ningún interruptor ni en el volcado ni en la carga.

Pat Farrell
fuente
También puede desactivar el registro binario durante la carga de su volcado
Cédric PEINTRE

Respuestas:

22

Tenga en cuenta estos puntos en su consideración, pueden ayudarlo en caso de generar el volcado y restaurarlo.

  1. Uso Extended insertsen vertederos.
  2. Volcado con --tabformato para que pueda usar mysqlimport, que es más rápido que mysql < dumpfile.
  3. Importar con múltiples hilos, uno para cada tabla.
  4. Utilice un motor de base de datos diferente si es posible. importar a un motor altamente transaccional como innodb es muy lento. Insertar en un motor no transaccional como MyISAM es mucho más rápido.
  5. Desactive las comprobaciones de clave externa y active la confirmación automática
  6. Si está importando a innodb, lo más efectivo que puede hacer es colocar innodb_flush_log_at_trx_commit = 2su my.cnf, temporalmente, mientras se ejecuta la importación. puede volver a ponerlo en 1 si necesita ACID

Darle una oportunidad..

Abdul Manaf
fuente
Tu pista innodb_flush_log_at_trx_commit = 2me salvó el día. Importar un volcado de 600 MB (como una sola gran transacción) hubiera necesitado 6 horas, pero con esta configuración temporal, ¡se hizo en 30 minutos!
Daniel Marschall
1
Las cosas que desearía saber antes de intentar cargar una base de datos de 80 gig de un volcado 4 días después de presionar 'enter' ... :)
Dmitri DB
7

Además de la respuesta de Abdul , me gustaría enfatizar la importancia de la --disable-keysopción, que apaga las teclas hasta que se carguen todos los datos para una tabla. Esta opción está habilitada como parte de la --optpalanca, que está habilitada de forma predeterminada, pero consideró importante señalar.

Si no omite las claves durante las inserciones, cada fila insertada reconstruirá el índice. Un proceso extremadamente lento.

Derek Downey
fuente
¿Es --disable-keys parte de mysqldump? o la recarga?
Pat Farrell
se agregará en el archivo de volcado
Derek Downey
--optestá
activado de
1
This option is effective only for nonunique indexes of MyISAM tables. It has no effect for other tables
Ethan Allen
7

He estado lidiando mucho con esto últimamente. Definitivamente puede mejorar el rendimiento de importación haciendo las importaciones en paralelo. La mayor parte de la desaceleración se basa en E / S, pero aún puede obtener una mejora del 40% volcando en tablas y luego importándolas, digamos 4 a la vez.

Puedes hacer esto con xargs como este:

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

tener los archivos comprimidos antes de enviarlos a mysql no ralentiza nada principalmente debido a la baja E / S. Mis tablas se comprimieron hasta aproximadamente 10: 1, por lo que ahorra mucho espacio en disco.

Descubrí que en máquinas de 4 núcleos, el uso de 4 procesos es óptimo, aunque solo marginalmente mejor que el uso de 3. Si tiene SSD o un RAID rápido, es probable que escale mejor.

Algunas otras cosas a tener en cuenta. Si tiene unidades de sector 4k, asegúrese de tener key_cache_block_size=4096y myisam_block_size=4K.

Si está utilizando tablas MyISAM, establezca la myisam_repair_threads = 2o superior. Esto permitirá que sus núcleos adicionales ayuden a reconstruir índices.

Asegúrate de no intercambiar nada. Si es así, reduzca el tamaño de la innodb_buffer_pool_size.

Creo que también obtuve un poco de aceleración con innnodb por estas opciones:

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

(los últimos tres no los probé extensamente; creo que los encontré como sugerencias en Internet). Tenga en cuenta que esto innodb_flush_log_at_commit=0puede provocar la corrupción con el bloqueo de mysql o la falta de energía.

Greg
fuente
Greg, bienvenido al sitio y gracias por tu respuesta. ¿Podría proporcionar algunas fuentes o razonamientos para sus sugerencias sobre *_block_sizey myisam_repair_threads? Además, no estoy seguro de que debamos ofrecer consejos para ajustar las variables basadas en 'sugerencias de Internet' :)
Derek Downey
5

Si tiene principalmente tablas MyISAM, debe aumentar el búfer de inserción masiva . Esto es lo que dice la documentación de MySQL sobre la configuración de bulk_insert_buffer_size :

MyISAM usa un caché especial en forma de árbol para hacer insertos masivos más rápido para INSERT ... SELECT, INSERT ... VALUES (...), (...), ..., y LOAD DATA INFILE cuando agrega datos a no vacío mesas. Esta variable limita el tamaño del árbol de caché en bytes por subproceso. Establecerlo en 0 deshabilita esta optimización. El valor predeterminado es 8 MB.

Hay dos cosas que debes hacer

1) Agréguelo a /etc/my.cnf

[mysqld]
bulk_insert_buffer_size=512M

2) Establecer el valor global para ello

SET GLOBAL bulk_insert_buffer_size = 1024 * 1024 * 512;

Si no tiene el privilegio de establecer bulk_insert_buffer_size a nivel mundial, haga esto

service mysql restart

Por supuesto, esto no es para InnoDB.

Desde otro ángulo, si las tablas son InnoDB o MyISAM, si los índices son más grandes que la tabla, es posible que tenga demasiados índices. Por lo general, considero que la recarga de un mysqldump MyISAM debería tomar 3 veces más tiempo que el mysqldump tardó en hacerse. También considero que la recarga de un mysqldump de InnoDB debería tomar 4 veces más tiempo que el mysqldump tardó en hacerse.

Si está excediendo la proporción 4: 1 para recargar un mysqldump, definitivamente tiene uno de dos problemas:

  • demasiados índices
  • índices demasiado grandes debido a columnas grandes

Puede medir el tamaño de sus datos por motor de almacenamiento con esto:

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;

Vea si los índices son casi tan grandes como los datos o incluso más grandes

También puede considerar deshabilitar el registro binario como este:

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

antes de volver a cargar el script

RolandoMySQLDBA
fuente
No sé cuántas veces me has salvado el día, pero seguro que ha sido mucho
Dmitri DB
2

Si omite el sistema de archivos por completo y simplemente canaliza la salida de mysqldump directamente en un proceso MySQL, debería ver notables mejoras de rendimiento. Cuánto depende en última instancia del tipo de unidad de disco que está utilizando, pero rara vez uso más archivos de volcado, independientemente del tamaño de la base de datos solo por esta razón.

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

Según mis experiencias, el disco duro es el cuello de botella. Olvídate de los discos giratorios. SSD es mejor, pero con mucho lo mejor es realizar esto en RAM, si tiene suficiente para mantener toda la base de datos por un corto tiempo. Aproximadamente:

  1. deja de mysqld
  2. alejar los contenidos existentes de / var / lib / mysql
  3. crear un directorio / var / lib / mysql vacío
  4. mount -t tmpfs -o size = 32g tmpfs / var / lib / mysql (ajustar el tamaño)
  5. crear una base de datos vacía (por ejemplo, mysql_install_db, o restaurar contenidos anteriores)
  6. iniciar mysqld
  7. importar
  8. deja de mysqld
  9. copiar / var / lib / mysql a mysql2
  10. umount mysql; rmdir mysql
  11. mover mysql2 a mysql
  12. comienza mysqld, sé feliz

Para mí, se puede importar un volcado de ~ 10G (/ var / lib / mysql que consume ~ 20G) en aproximadamente 35 minutos (mydumper / myloader), 45 minutos (mysqldump --tab / mysqlimport), 50 minutos (mysqldump / mysql) , en un Xeon de 3.2xHz de 2x6 núcleos.

Si no tiene suficiente RAM en una sola máquina, pero tiene varias computadoras una al lado de la otra con una red rápida, sería interesante ver si sus RAM se pueden unir con nbd (dispositivo de bloqueo de red). O, con innodb_file_per_table, probablemente pueda repetir el proceso anterior para cada tabla.

egmont
fuente
Por curiosidad intenté almacenar el mysql datadir en RAM para compararlo con un SSD (SSDSC2BB48 para los interesados) para una base de datos de 2 GB. Los resultados fueron IDÉNTICOS, ambos tomaron 207-209 segundos. Teniendo en cuenta el hecho de que también debe iniciar / detener mysql y copiar los directorios, usar un disco RAM en lugar del SSD fue mucho más lento en mi caso
Shocker
Si le tomó ~ 3-4 minutos, supongo que tiene una base de datos significativamente más pequeña de lo que trata este tema. Sería interesante conocer sus experiencias con bases de datos de gran tamaño similares a las mencionadas en este tema.
egmont