¿Cómo se elimina la fragmentación de las tablas de InnoDB?


13

Tengo una base de datos que tiene varias tablas.

Quiero eliminar algunos registros de las tablas que dicen que el número de registros es más de 20K o 50K.

Todas las tablas son InnoDB. Y file_per_tablese fue .

Cuando elimine los registros de varias tablas, habrá fragmentación en las tablas.

¿Hay alguna forma de eliminar la fragmentación?

Actualización el 17 de abril

mysql> select TABLE_NAME, TABLE_SCHEMA, Data_free from information_schema.TABLES where TABLE_SCHEMA NOT IN ('information_schema', 'mysql') and Data_Free >0;
+-----------------+--------------+-----------+
| TABLE_NAME      | TABLE_SCHEMA | Data_free |
+-----------------+--------------+-----------+
| City            | world_innodb |   5242880 |
| City_Copy       | world_innodb |   5242880 |
| Country         | world_innodb |   5242880 |
| CountryLanguage | world_innodb |   5242880 |
| a               | world_innodb |   5242880 |
| t1              | world_innodb |   5242880 |
| t2              | world_innodb |   5242880 |
+-----------------+--------------+-----------+
7 rows in set (0.00 sec)

Entonces, mi pregunta es cómo decidiré si mis tablas están fragmentadas o no.



1
Y un artículo InnoDB: cuida la fragmentación del sitio del blog de Percona.
ypercubeᵀᴹ

Respuestas:


14

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 TABLEcontra 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;

no creo que / var / lib / mysql / ibdata1 esté muy ocupado si está utilizando la opción recomendada innodb_file_per_table = 1
CrackerJack9

1
@ CrackerJack9 ibdata1 está increíblemente ocupado debido a lo que contiene: 1) Información de búfer de doble escritura, 2) Insertar búfer para índices secundarios, 3) Diccionario de datos, 4) Segmentos de reversión, 5) Deshacer espacio de tabla. Por favor Goto scribd.com/doc/31337494/XtraDB-InnoDB-internals-in-drawing para una representación pictórica de estas cosas. Incluso con la eliminación de páginas de datos e índices para tablas InnoDB, ibdata1 aún puede crecer significativamente en un entorno transaccional alto.
RolandoMySQLDBA

1
@ CrackerJack9 Tengo una publicación adicional que discute la actividad adicional sobre ibdata1: dba.stackexchange.com/a/23367/877
RolandoMySQLDBA

No me había dado cuenta de que todavía se usaba tanto. ¡Apreciado enormemente!
CrackerJack9

@RolandoMySQLDBA ¿Puedes hacer pop en el montón cuando tienes tiempo?
ypercubeᵀᴹ 05 de

5

Si elimina filas con frecuencia (o actualiza filas con tipos de datos de longitud variable), puede terminar con una gran cantidad de espacio desperdiciado en sus archivos de datos, similar a la fragmentación del sistema de archivos.

Si no está utilizando la innodb_file_per_tableopción, lo único que puede hacer al respecto es exportar e importar la base de datos, un procedimiento que requiere mucho tiempo y disco.

Pero si está usando innodb_file_per_table, ¡puede identificar y reclamar este espacio!

Antes de 5.1.21, el contador de espacio libre está disponible en la columna table_comment de information_schema.tables. Aquí hay algunos SQL para identificar tablas con al menos 100M (en realidad 97.65M) de espacio libre:

SELECCIONE table_schema, table_name, table_comment FROM
information_schema.tables DONDE EL MOTOR COMO 'InnoDB' Y table_comment RLIKE 'InnoDB free: ([0-9] {6,}). *';

A partir de 5.1.21, esto se movió a la columna data_free (un lugar mucho más apropiado):

SELECCIONE table_schema, table_name, data_free / 1024/1024 AS data_free_MB FROM information_schema.tables DONDE EL MOTOR COMO 'InnoDB' Y data_free> 100 * 1024 * 1024;

Puede recuperar el espacio perdido reconstruyendo la tabla. La mejor manera de hacer esto es usar 'alter table' sin cambiar realmente nada:

ALTER TABLE `TableName` ENGINE=InnoDB;

Esto es lo que hace MySQL detrás de escena si ejecuta 'optimizar tabla' en una tabla InnoDB. Resultará en un bloqueo de lectura, pero no un bloqueo de tabla completo. El tiempo que tarda depende completamente de la cantidad de datos en la tabla (pero no del tamaño del archivo de datos). Si tiene una tabla con un alto volumen de eliminaciones o actualizaciones, es posible que desee ejecutarla mensualmente o incluso semanalmente.


Una cosa más: no puedo entender qué significa data_free> 100 * 1024 * 1024 ... ¿Y cuando vi el resultado no puedo decidir si la tabla está fragmentada o no? ¿Hay alguna manera de que yo puede decir que la tabla está fragmentada o no fragmentada?
Abdul Manaf

Echa un vistazo a la parte de mi actualización.
Abdul Manaf
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.