Abordé esto en StackOverflow en octubre de 2010 .
Tenga en cuenta el archivo más ocupado en la infraestructura de InnoDB: / var / lib / mysql / ibdata1
Este archivo normalmente contiene cuatro tipos de información
- Datos de tabla
- Índices de tabla
- Datos MVCC (Control de concurrencia multiversionante)
- Metadatos de tabla (Lista de ID de espacios de tabla)
Ejecutar OPTIMIZE TABLE
contra una tabla InnoDB almacenada en ibdata1 hace dos cosas:
- Hace que los datos e índices de la tabla sean contiguos dentro de ibdata1, por lo tanto, es más rápido acceder
- Hace que ibdata1 crezca porque los datos contiguos y las páginas de índice se agregan a ibdata1
Si bien puede segregar los datos de la tabla y los índices de la tabla de ibdata1 y administrarlos de forma independiente utilizando innodb_file_per_table , la gran brecha de espacio en disco en ibdata1 simplemente no desaparecerá y no se puede reclamar. Debes hacer más.
Para reducir ibdata1 de una vez por todas , debe hacer lo siguiente:
1) MySQL Vuelca todas las bases de datos en un archivo de texto SQL (llámalo /root/SQLData.sql)
2) Descarte todas las bases de datos (excepto el esquema mysql)
3) Apagar mysql
4) Agregue las siguientes líneas a /etc/my.cnf
[mysqld]
innodb_file_per_table
innodb_flush_method=O_DIRECT
innodb_log_file_size=1G
innodb_buffer_pool_size=4G
Nota al margen: cualquiera que sea su conjunto para innodb_buffer_pool_size, asegúrese de que innodb_log_file_size sea el 25% de innodb_buffer_pool_size.
5) Eliminar ibdata1, ib_logfile0 e ib_logfile1
En este punto, solo debe haber el esquema mysql en / var / lib / mysql
6) Reiniciar mysql
Esto recreará ibdata1 a 10 o 18 MB (dependiendo de la versión de MySQL), ib_logfile0 e ib_logfile1 a 1G cada uno
7) Recargar /root/SQLData.sql en mysql
ibdata1 crecerá pero solo contendrá metadatos de tabla. De hecho, crecerá muy lentamente con los años. La única forma en que ibdata1 crece rápidamente es si tiene uno o más de los siguientes:
- Una gran cantidad de DDL (
CREATE TABLE
, DROP TABLE
, ALTER TABLE
)
- Muchas transacciones
- Muchos cambios para confirmar por transacción
Cada tabla InnoDB existirá fuera de ibdata1
Supongamos que tiene una tabla InnoDB llamada mydb.mytable. Si accede a / var / lib / mysql / mydb, verá dos archivos que representan la tabla
- mytable.frm (encabezado del motor de almacenamiento)
- mytable.ibd (Página principal de datos de tabla e índices de tabla para mydb.mytable)
ibdata1 nunca contendrá más datos e índices de InnoDB.
Con la opción innodb_file_per_table en /etc/my.cnf, puede ejecutar OPTIMIZE TABLE mydb.mytable;
y el archivo /var/lib/mysql/mydb/mytable.ibd realmente se reducirá.
He hecho esto muchas veces en mi carrera como DBA MySQL
De hecho, la primera vez que hice esto, colapsé un archivo ibdata1 de 50 GB en 500 MB.
Darle una oportunidad. Si tiene más preguntas sobre esto, envíeme un correo electrónico. Créeme. ¡Esto funcionará a corto plazo y a largo plazo!
ACTUALIZACIÓN 2012-04-19 09:23 EDT
Después de ejecutar los pasos anteriores, ¿cómo puede determinar qué tablas deben desfragmentarse? Es posible averiguarlo, pero tendrá un script.
Aquí hay un ejemplo: suponga que tiene la tabla mydb.mytable
. Con innodb_file_per_table habilitado, tiene el archivo /var/lib/mysql/mydb/mytable.ibd
Tendrás que recuperar dos números
TAMAÑO DE ARCHIVO DESDE EL SO: Puede determinar el tamaño de archivo desde el SO de esta manera
ls -l /var/lib/mysql/mydb/mytable.ibd | awk '{print $5}'
FILESIZE FROM INFORMATION_SCHEMA: Puede determinar el tamaño del archivo desde information_schema.tables de esta manera:
SELECT (data_length+index_length) tblsize FROM information_schema.tables
WHERE table_schema='mydb' AND table_name='mytable';
Simplemente reste el valor de INFORMATION_SCHEMA del valor de OS y divida la diferencia entre el valor de INFORMATION_SCHEMA.
A partir de ahí, usted decidiría qué porcentaje considera necesario desfragmentar esa tabla. Por supuesto, lo desfragmenta con uno de los siguientes comandos:
OPTIMIZE TABLE mydb.mytable;
o
ALTER TABLE mydb.mytable ENGINE=InnoDB;