Cómo reducir / purgar el archivo ibdata1 en MySQL

561

Estoy usando MySQL en localhost como una "herramienta de consulta" para realizar estadísticas en R, es decir, cada vez que ejecuto un script R, creo una nueva base de datos (A), creo una nueva tabla (B), importo los datos a B , enviar una consulta para obtener lo que necesito, y luego soltar B y soltar A.

Me está funcionando bien, pero me doy cuenta de que el tamaño del archivo ibdata está aumentando rápidamente, no almacené nada en MySQL, pero el archivo ibdata1 ya excedió los 100 MB.

Estoy usando más o menos la configuración predeterminada de MySQL para la configuración, ¿hay alguna manera de que pueda reducir / purgar automáticamente el archivo ibdata1 después de un período de tiempo fijo?

lokheart
fuente
Referencia adicional: ibdata1 crece exponencialmente cuando se configura
innodb_file_per_table

Respuestas:

778

Eso ibdata1no se está reduciendo es una característica particularmente molesta de MySQL. El ibdata1archivo no puede reducirse a menos que elimine todas las bases de datos, elimine los archivos y vuelva a cargar un volcado.

Pero puede configurar MySQL para que cada tabla, incluidos sus índices, se almacene como un archivo separado. De esa manera ibdata1no crecerá tanto. Según el comentario de Bill Karwin, esto está habilitado de forma predeterminada a partir de la versión 5.6.6 de MySQL.

Hace un tiempo hice esto. Sin embargo, para configurar su servidor para usar archivos separados para cada tabla, necesita cambiar my.cnfpara habilitar esto:

[mysqld]
innodb_file_per_table=1

http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html

Como desea recuperar el espacio ibdata1, debe eliminar el archivo:

  1. Realice una mysqldumpde todas las bases de datos, procedimientos, disparadores, etc., excepto las bases de datos mysqlyperformance_schema
  2. Descarte todas las bases de datos excepto las 2 bases de datos anteriores
  3. Deja de mysql
  4. Eliminar ibdata1y ib_logarchivos
  5. Comience mysql
  6. Restaurar desde el volcado

Cuando inicie MySQL en el paso 5 , se volverán a crear los archivos ibdata1y ib_log.

Ahora estás listo para ir. Cuando crea una nueva base de datos para análisis, las tablas se ubicarán en ibd*archivos separados , no en ibdata1. Como suele soltar la base de datos poco después, los ibd*archivos se eliminarán.

http://dev.mysql.com/doc/refman/5.1/en/drop-database.html

Probablemente has visto esto:
http://bugs.mysql.com/bug.php?id=1341

Al usar el comando ALTER TABLE <tablename> ENGINE=innodbo OPTIMIZE TABLE <tablename>uno puede extraer datos e páginas de índice de ibdata1 para separar archivos. Sin embargo, ibdata1 no se reducirá a menos que realice los pasos anteriores.

En cuanto a information_schemaeso, eso no es necesario ni posible abandonar. De hecho, es solo un montón de vistas de solo lectura, no tablas. Y no hay archivos asociados con ellos, ni siquiera un directorio de base de datos. El informations_schemaes el uso de la memoria db-motor y se deja caer y regenerados en parada / reinicio de mysqld. Ver https://dev.mysql.com/doc/refman/5.7/en/information-schema.html .

John P
fuente
16
@JordanMagnuson No te molestes en soltar información_esquema. De hecho, es solo un montón de vistas de solo lectura, no tablas. Y no hay archivos asociados con ellos. Ni siquiera hay un directorio para la base de datos. Informations_schema está utilizando la memoria db-engine y se descarta y se regenera al detener / reiniciar mysqld. Ver dev.mysql.com/doc/refman/5.5/en/information-schema.html . En cuanto a performance_schema, no he usado ese esquema yo mismo.
John P
44
No sé si esto es algo reciente, pero una vez que la opción innodb_file_per_table esté habilitada, simplemente puede ejecutar "ALTER TABLE <tablename> ENGINE = InnoDB" (incluso si ya es InnoDB) y moverá la tabla a su archivo individual . No es necesario descartar bases de datos y demás.
CR.
3
+1 FWIW, MySQL 5.6 habilita innodb_file_per_tablepor defecto.
Bill Karwin
3
Sí, se espera que ibdata1 esté presente junto con los otros archivos. El archivo ibdata1 aún conservará metadatos sobre tablas, el registro de deshacer y los buffers.
John P
1
Me he quedado sin espacio en mi servidor debido al archivo ibdata1, por lo que ni siquiera puedo volcar las bases de datos. ¿Sería lo mismo mover los archivos a / var / lib / mysql (excepto "mysql", "ibdata1", "ib_logfile0" y "ib_logfile1") y luego seguir los pasos? Ver stackoverflow.com/questions/2482491/…
Sophivorus el
47

Agregando a la respuesta de John P ,

Para un sistema Linux, los pasos 1-6 se pueden lograr con estos comandos:

  1. mysqldump -u [username] -p[root_password] [database_name] > dumpfilename.sql
  2. DROP DATABASE [database_name];
  3. sudo /etc/init.d/mysqld stop
  4. sudo rm /var/lib/mysql/ibdata1
    sudo rm /var/lib/mysql/ib_logfile (y elimine cualquier otro ib_logfile que pueda nombrarse ib_logfile0, ib_logfile1etc.)
  5. sudo /etc/init.d/mysqld start
  6. create database [database_name];
  7. mysql -u [username]-p[root_password] [database_name] < dumpfilename.sql

Advertencia: estas instrucciones harán que pierda otras bases de datos si tiene otras bases de datos en esta instancia de mysql. Asegúrese de que los pasos 1,2 y 6,7 se modifiquen para cubrir todas las bases de datos que desea conservar.

Vinay Vemula
fuente
66
Debe repetir 1,2 y 6 para cada base de datos que tenga tablas InnoDB.
Marqués de Lorne
44
Necesita un par de pasos más entre # 5 y # 6. Debe volver a crear la base de datos y volver a asignar permisos. Entonces, desde el símbolo del sistema del cliente mysql create database database_name;y luegogrant all privileges on database_name.* to 'username'@'localhost' identified by 'password';
fred
1
@fred No necesitaba otorgar privilegios al hacer esto. ¿Posiblemente porque recreé la base de datos con el mismo nombre?
crmpicco
2
Para escribir la contraseña en un Password:indicador (que es una práctica más segura), simplemente colóquela -psin ninguna contraseña real.
ADTC
Los desencadenantes, eventos y rutinas / funciones no se vuelcan a menos que le indique a mysqldump que lo haga. Agregue también los desencadenantes, los eventos y las rutinas si alguna de sus bases de datos los contiene. Además, simplemente descargue con --all-bases de datos para volcar todas las bases de datos a la vez en lugar de una por una.
Friek
34

Cuando elimina las tablas innodb, MySQL no libera el espacio dentro del archivo ibdata, es por eso que sigue creciendo. Estos archivos casi nunca se reducen.

Cómo reducir un archivo ibdata existente:

http://dev.mysql.com/doc/refman/5.5/en/innodb-resize-system-tablespace.html

Puede hacer un script para esto y programar el script para que se ejecute después de un período de tiempo fijo, pero para la configuración descrita anteriormente parece que múltiples espacios de tabla son una solución más fácil.

Si usa la opción de configuración innodb_file_per_table, crea múltiples espacios de tabla. Es decir, MySQL crea archivos separados para cada tabla en lugar de un archivo compartido. Estos archivos separados se almacenan en el directorio de la base de datos y se eliminan cuando elimina esta base de datos. Esto debería eliminar la necesidad de reducir / purgar archivos ibdata en su caso.

Más información sobre múltiples espacios de tabla:

http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html

titanoboa
fuente
primer enlace roto, coincidencia más cercana que pude encontrar: dev.mysql.com/doc/refman/5.5/en/…
BlackICE
14

Si usa el motor de almacenamiento InnoDB para (algunas de) sus tablas MySQL, probablemente ya haya encontrado un problema con su configuración predeterminada. Como habrá notado en el directorio de datos de MySQL (en Debian / Ubuntu - / var / lib / mysql) se encuentra un archivo llamado 'ibdata1'. Contiene casi todos los datos de InnoDB (no es un registro de transacciones) de la instancia de MySQL y podría ser bastante grande. Por defecto, este archivo tiene un tamaño inicial de 10Mb y se extiende automáticamente. Desafortunadamente, por diseño, los archivos de datos InnoDB no pueden reducirse. Es por eso que DELETEs, TRUNCATE, DROP, etc. no reclamarán el espacio utilizado por el archivo.

Creo que puede encontrar una buena explicación y solución allí:

http://vdachev.net/2007/02/22/mysql-reducing-ibdata1/

Vik
fuente
11

Rápidamente escribió el procedimiento de respuesta aceptado en bash:

#!/usr/bin/env bash
DATABASES="$(mysql -e 'show databases \G' | grep "^Database" | grep -v '^Database: mysql$\|^Database: binlog$\|^Database: performance_schema\|^Database: information_schema' | sed 's/^Database: //g')"
mysqldump --databases $DATABASES -r alldatabases.sql && echo "$DATABASES" | while read -r DB; do
    mysql -e "drop database \`$DB\`"
done && \
    /etc/init.d/mysql stop && \
    find /var/lib/mysql -maxdepth 1 -type f \( -name 'ibdata1' -or -name 'ib_logfile*' \) -delete && \
    /etc/init.d/mysql start && \
    mysql < alldatabases.sql && \
    rm -f alldatabases.sql

Guardar como purge_binlogs.shy ejecutar como root.

Excluye mysql, information_schema, performance_schema(y binlogdirectorio).

Asume que tiene credenciales de administrador /root/.my.cnfy que su base de datos vive en el /var/lib/mysqldirectorio predeterminado .

También puede purgar registros binarios después de ejecutar este script para recuperar más espacio en disco con:

PURGE BINARY LOGS BEFORE CURRENT_TIMESTAMP;
Pierre-Alexis de Solminihac
fuente
Todavía no estoy seguro de por qué, pero hoy algunas de mis tablas de InnoDB se dañaron durante un proceso similar, por lo que no eliminaría alldatabases.sqlantes de verificar si todas las tablas están en buen estado. En cuanto a algunas mejoras: configurar innodb_fast_shutdown=0antes de apagar, configurar autocommit=0antes de importar el archivo SQL, ejecutar COMMITy configurar autocommit=1después de importar el archivo SQL, usar mysqlcheck --all-databasesantes de eliminar la copia de seguridad.
Victor
6

Si su objetivo es monitorear el espacio libre de MySQL y no puede evitar que MySQL reduzca su archivo ibdata, hágalo mediante comandos de estado de la tabla. Ejemplo:

MySQL> 5.1.24:

mysqlshow --status myInnodbDatabase myTable | awk '{print $20}'

MySQL <5.1.24:

mysqlshow --status myInnodbDatabase myTable | awk '{print $35}'

Luego compare este valor con su archivo ibdata:

du -b ibdata1

Fuente: http://dev.mysql.com/doc/refman/5.1/en/show-table-status.html

Cyno
fuente
4

En una nueva versión de mysql-server, las recetas anteriores destruirán la base de datos "mysql". En la versión anterior funciona. En las nuevas tablas, algunas tablas cambian al tipo de tabla INNODB, y al hacerlo las dañará. La forma más fácil es:

  • volcar todas sus bases de datos
  • desinstalar mysql-server,
  • agregar permaneció my.cnf:
    [mysqld]
    innodb_file_per_table=1
  • borrar todo en / var / lib / mysql
  • instalar mysql-server
  • restaurar usuarios y bases de datos
llave ajustable
fuente
1

Como ya se señaló, no puede reducir ibdata1 (para hacerlo, debe volcar y reconstruir), pero a menudo tampoco es necesario.

Usando autoextend (probablemente la configuración de tamaño más común) ibdata1 preasigna el almacenamiento, creciendo cada vez que está casi lleno. Eso hace que las escrituras sean más rápidas ya que el espacio ya está asignado.

Cuando elimina datos, no se reduce, pero el espacio dentro del archivo se marca como no utilizado. Ahora, cuando inserte datos nuevos, reutilizará el espacio vacío en el archivo antes de seguir creciendo.

Por lo tanto, solo seguirá creciendo si realmente necesita esos datos. A menos que realmente necesite el espacio para otra aplicación, probablemente no haya razón para reducirlo.

steveayre
fuente
66
Creo que eres un poco despectivo de la necesidad de liberar el espacio.
Drawish
2
Tengo una partición de estado sólido 60Gig. Me quedo sin espacio rápidamente, ya que trabajo con bases de datos de 4 + conciertos. Estoy buscando mover mysql a otra partición pronto, pero esta pregunta y sus respuestas me ayudarán mientras tanto
NullVoxPopuli
3
Gracias por esta respuesta, es muy útil. He borrado algunas tablas de datos heredados ... es bueno saber que el tamaño en el disco no volverá a crecer pronto.
Brad
1
Tengo un archivo 500G ibdata1, pero casi todos los datos almacenados en él ahora se almacenan en archivos por base de datos. ¡Necesito reducir este desperdicio de espacio colosal!
frankster
2
Completa tontería! Es necesario recortar un archivo que sigue hinchándose, ya sea que se esté quedando sin espacio o no . Yo lo llamaría a storage leak.
ADTC