No se deje engañar por el mensaje de error The table 'my_table' is full
. Este raro escenario no tiene absolutamente nada que ver con el espacio en disco. Esta condición completa de la tabla tiene que ver con la fontanería interna de InnoDB.
Primero, eche un vistazo a este diagrama de la arquitectura InnoDB
Tenga en cuenta que el espacio de tabla del sistema (el archivo ibdata) solo tiene 128 segmentos de reversión y 1023 ranuras de reversión por segmento de reversión. Esto pone límites al tamaño de la capacidad de reversión de una transacción. En otras palabras, si un solo segmento de reversión necesita más de 1023 ranuras para admitir una transacción, la transacción alcanzará esa table is full
condición.
Piense en el restaurante Red Lobster en Nueva Jersey . Puede tener una capacidad de 200 personas. Si el restaurante está lleno, una fila de personas puede salir a esperar. Si las personas en la fila se impacientan, pueden irse porque el restaurante está lleno. Obviamente, la solución no sería hacer que Nueva Jersey sea más grande (u obtener más espacio en disco). La solución sería agrandar el restaurante Red Lobster. De esa manera, puede aumentar la capacidad de asientos a, digamos, 240. Incluso con eso, se puede formar una fila afuera si más de 240 personas deciden venir a Red Lobster.
Solo para darle un ejemplo, tenía un cliente con 2TB de espacio de tabla del sistema y se deshabilitó innodb_file_per_table . (346G para ibdata1, el restablecimiento para ibdata2). Ejecuté esta consulta
SELECT SUM(data_length+index+length) InnoDBDataIndexSpace
FROM information_schema.tables WHERE engine='InnoDB';
Luego, resté InnoDBDataIndexSpace de la suma de los tamaños de archivo para ibdata1 e ibdata2. Tengo dos cosas que me sorprendieron
- Quedaban 106 GB dentro del espacio de tabla del sistema.
- Tengo esta misma
Table is Full
condición
Esto significa que el 106GB estaba utilizando para la fontanería interna de InnoDB. El cliente estaba usando ext3 en ese momento.
La solución para mí fue agregar ibdata3. Discutí esto en mi publicación anterior ¿Cómo resolver "La tabla ... está llena" con "innodb_file_per_table"?
He discutido esto en otras publicaciones también
Tenga en cuenta que esta condición puede ocurrir incluso si innodb_file_per_table estaba habilitado. ¿Cómo? Los retrocesos y los registros de deshacer son la fuente de picos incontrolados, es el crecimiento de ibdata1 .
TU PREGUNTA REAL
Como está agregando un índice a una tabla y obteniendo Table is Full
, la tabla debe ser enorme y no puede caber dentro de un solo segmento de reversión. Debes hacer lo siguiente:
PASO 01
Obtener los datos en un archivo de volcado
mysqldump --no-create-info mydb mytable > table_data.sql
PASO 02
Inicie sesión en MySQL y ejecute esto
USE mydb
CREATE TABLE mytable_new LIKE mytable;
ALTER TABLE mytable_new ADD INDEX ... ;
ALTER TABLE mytable RENAME mytable_old;
ALTER TABLE mytable_new RENAME mytable;
PASO 03
Cargue la tabla con el índice adicional con los datos.
mysql -Dmydb < table_data.sql
Eso es todo.
Vea, el problema es que ALTER TABLE intentará inyectar todas las filas en su tabla enorme como una sola transacción. El uso de mysqldump insertará los datos en la tabla (ahora con un nuevo índice) miles de filas a la vez, no todas las filas en una sola transacción.
No se preocupe por what if this doesn't work?
la tabla original se nombrará mytable_old
en caso de cualquier cosa. Puede servir como respaldo. Puede soltar la copia de seguridad cuando sepa que la nueva tabla funciona para usted.
Darle una oportunidad !!!
ACTUALIZACIÓN 2014-06-16 11:13 EDT
Si le preocupa el volcado de los datos más grandes, simplemente gzip.
Puedes hacer los mismos pasos, pero de la siguiente manera
PASO 01
Obtener los datos en un archivo de volcado
mysqldump --no-create-info mydb mytable | gzip > table_data.sql.gz
PASO 02
Inicie sesión en MySQL y ejecute esto
USE mydb
CREATE TABLE mytable_new LIKE mytable;
ALTER TABLE mytable_new ADD INDEX ... ;
ALTER TABLE mytable RENAME mytable_old;
ALTER TABLE mytable_new RENAME mytable;
PASO 03
Cargue la tabla con el índice adicional con los datos.
gzip -d < table_data.sql.gz | mysql -Dmydb
o
gunzip < table_data.sql.gz | mysql -Dmydb
ACTUALIZACIÓN 2014-06-16 12:55 EDT
Acabo de pensar en otro aspecto con respecto a este tema.
Como está haciendo DDL y no DML, es posible que esto no sea una tubería interna de InnoDB. Dado que DDL no puede revertir para InnoDB , el problema tiene que ser la plomería externa. ¿Dónde se está obstruyendo esta tubería externa? Sospecho que la carpeta temporal para el sistema operativo. ¿Por qué?
140616 13:04:33 InnoDB: Error: Write to file (merge) failed at offset 3 1940914176.
InnoDB: 1048576 bytes should have been written, only 970752 were written.
InnoDB: Operating system error number 0.
InnoDB: Check that your OS and file system support files of this size.
InnoDB: Check also that the disk is not full or a disk quota exceeded.
InnoDB: Error number 0 means 'Success'.
InnoDB: Some operating system error numbers are described at
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/operating-system-error-codes.html
140616 13:04:33 [ERROR] /usr/libexec/mysqld: The table 'my_table' is full
¿Ves el disk quota exceeded
? ¿Dónde se impone esta cuota de disco?
Ejecute esta consulta
SHOW GLOBAL VARIABLES LIKE 'tmpdir';
Dijiste que es /var/lib/mysqltmp
Ahora, ejecuta esto en el sistema operativo
df -h /var/lib/mysqltmp
Algo me dice que el espacio se /var/lib/mysqltmp
estaba acabando Después de todo, solo tienes 14G gratis. A los ojos del DDL (para crear el índice), ocurrió una reversión, no en el archivo ibdata1, sino en la tmpdir
ubicación. Si /var/lib/mysqltmp
no está montado en ningún lugar, los datos temporales se escriben en la partición raíz. Si /var/lib/mysqltmp
está montado en algún lugar, entonces ese montaje se está llenando con datos de fila. En cualquier caso, no hay suficiente espacio para completar el DDL.
Tienes dos opciones aquí
OPCIÓN 1
También puede crear un disco grande (quizás con más de 100 GB) y montarlo /var/lib/mysqltmp
en ese disco grande.
OPCION 2
Mis sugerencias de 3 pasos aún deberían funcionar, incluso con el espacio en disco limitado que tiene
COMENTARIO
Es una pena que el mensaje de error que publicaste dice
InnoDB: Operating system error number 0.
InnoDB: Error number 0 means 'Success'.
Esto significa que el sistema operativo está bien. Tampoco existe ningún número de error asociado para esta situación.
Hay otra cosa que debes saber. La documentación de MySQL dice que la creación rápida de índices para InnoDB todavía va al disco :
Durante la creación del índice, los archivos se escriben en el directorio temporal ($ TMPDIR en Unix,% TEMP% en Windows o el valor de la variable de configuración --tmpdir). Cada archivo temporal es lo suficientemente grande como para contener una columna que forma el nuevo índice, y cada uno se elimina tan pronto como se combina en el índice final.
Debido a una limitación de MySQL, la tabla se copia, en lugar de usar "Creación rápida de índice" cuando se crea un índice en una TABLA TEMPORAL. Esto ha sido reportado como MySQL Bug # 39833 .
ACTUALIZACIÓN 2014-06-16 13:58 EDT
[mysqld]
datadir = /mnt/cbsvolume1/var/lib/mysql
tmpdir = /mnt/cbsvolume1/var/lib/mysql
Asegúrate de que /mnt/cbsvolume1/var/lib/mysql
tenga 100G o más gratis