Per favore, non fatevi ingannare dal messaggio di errore The table 'my_table' is full
. Questo raro scenario non ha assolutamente nulla a che fare con lo spazio su disco. Questa condizione completa della tabella ha a che fare con l'impianto idraulico interno di InnoDB.
Innanzitutto, dai un'occhiata a questo diagramma dell'architettura InnoDB
Si noti che il tablespace di sistema (il file ibdata) ha solo 128 segmenti di rollback e 1023 slot di rollback per segmento di rollback. Ciò pone limiti alla dimensione della capacità di rollback di una transazione. In altre parole, se un singolo segmento di rollback ha bisogno di più di 1023 slot per supportare una transazione, la transazione colpirà quella table is full
condizione.
Pensa al ristorante Red Lobster nel New Jersey . Può avere una capacità di 200 persone. Se il ristorante è pieno, una fila di persone può uscire per aspettare. Se le persone sulla linea diventano impazienti, potrebbero andarsene perché il ristorante è pieno. Ovviamente, la soluzione non sarebbe quella di ingrandire il New Jersey (o ottenere più spazio su disco). La soluzione sarebbe quella di ingrandire il ristorante Red Lobster. In questo modo è possibile aumentare la capacità di posti a sedere, diciamo, a 240. Anche con ciò, una linea può formarsi all'esterno se più di 240 persone decidono di venire a Red Lobster.
Solo per fare un esempio, avevo un client con 2 TB di tablespace di sistema e innodb_file_per_table era disabilitato. (346G per ibdata1, il reset per ibdata2). Ho eseguito questa query
SELECT SUM(data_length+index+length) InnoDBDataIndexSpace
FROM information_schema.tables WHERE engine='InnoDB';
Successivamente, ho sottratto InnoDBDataIndexSpace dalla somma delle dimensioni dei file per ibdata1 e ibdata2. Ho due cose che mi hanno scioccato
- Rimanevano 106 GB nel tablespace di sistema.
- Ho le stesse
Table is Full
condizioni
Ciò significa che il 106GB stava usando per l'impianto idraulico interno di InnoDB. Il client stava usando ext3 al momento.
La soluzione per me era aggiungere ibdata3. Ne ho discusso nel mio vecchio post Come risolvere "La tabella ... è piena" con "innodb_file_per_table"?
Ne ho discusso anche in altri post
Tieni presente che questa condizione può verificarsi anche se innodb_file_per_table è stato abilitato. Come? I rollback e i log di annullamento sono la fonte di picchi incontrollati è la crescita di ibdata1 .
LA TUA DOMANDA ATTUALE
Dal momento che stai aggiungendo un indice a una tabella e stai ottenendo Table is Full
, la tabella deve essere enorme e non può rientrare in un singolo segmento di rollback. È necessario effettuare le seguenti operazioni:
PASSO 01
Ottieni i dati in un file di dump
mysqldump --no-create-info mydb mytable > table_data.sql
PASSO 02
Accedi a MySQL ed esegui questo
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;
PASSO 03
Carica la tabella con l'indice aggiuntivo con i dati
mysql -Dmydb < table_data.sql
È tutto.
Vedi, il problema è che ALTER TABLE tenterà di iniettare tutte le righe nella tua enorme tabella come un'unica transazione. L'uso di mysqldump inserirà i dati nella tabella (ora con un nuovo indice) migliaia di righe alla volta, non tutte le righe in un'unica transazione.
Non preoccuparti what if this doesn't work?
La tabella originale verrà nominata mytable_old
in caso di qualcosa. può servire come backup. Puoi eliminare il backup quando sai che la nuova tabella funziona per te.
Provaci !!!
AGGIORNAMENTO 2014-06-16 11:13 EDT
Se sei preoccupato per il dump dei dati più grandi, basta decomprimerlo.
Puoi fare gli stessi passaggi, ma come segue
PASSO 01
Ottieni i dati in un file di dump
mysqldump --no-create-info mydb mytable | gzip > table_data.sql.gz
PASSO 02
Accedi a MySQL ed esegui questo
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;
PASSO 03
Carica la tabella con l'indice aggiuntivo con i dati
gzip -d < table_data.sql.gz | mysql -Dmydb
o
gunzip < table_data.sql.gz | mysql -Dmydb
AGGIORNAMENTO 2014-06-16 12:55 EDT
Ho appena pensato a un altro aspetto in merito a questo problema.
Dato che stai facendo DDL e non DML, è possibile che questo non sia un impianto idraulico interno di InnoDB. Poiché DDL non può eseguire il rollback per InnoDB , il problema deve essere un impianto idraulico esterno. Dov'è intasato questo impianto idraulico esterno? Ho il sospetto che la cartella temporanea per il sistema operativo. Perché?
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
Vedi il disk quota exceeded
? Dove viene imposta questa quota del disco?
Esegui questa query
SHOW GLOBAL VARIABLES LIKE 'tmpdir';
Hai detto che lo è /var/lib/mysqltmp
Ora eseguilo nel sistema operativo
df -h /var/lib/mysqltmp
Qualcosa mi dice che lo spazio per si /var/lib/mysqltmp
stava esaurendo Dopo tutto, hai solo 14G gratis. Agli occhi del DDL (per creare l'indice), si è verificato un rollback, non nel file ibdata1, ma nella tmpdir
posizione. Se /var/lib/mysqltmp
non è montato da nessuna parte, i dati temporanei vengono scritti nella partizione radice. Se /var/lib/mysqltmp
è montato da qualche parte, quel mount viene riempito con i dati di riga. In entrambi i casi, non c'è spazio sufficiente per completare il DDL.
Hai due opzioni qui
OPZIONE 1
Puoi anche creare un disco di grandi dimensioni (forse con 100 + GB) e montare /var/lib/mysqltmp
su quel disco di grandi dimensioni.
OPZIONE 2
I miei suggerimenti in 3 passaggi dovrebbero comunque funzionare, anche con lo spazio su disco limitato che hai
COMMENTO
È un peccato che dice il messaggio di errore che hai postato
InnoDB: Operating system error number 0.
InnoDB: Error number 0 means 'Success'.
Ciò significa che il sistema operativo va bene. Inoltre non esiste alcun numero di errore associato per questa situazione.
C'è un'altra cosa che dovresti sapere. La documentazione di MySQL afferma che la creazione rapida dell'indice per InnoDB va ancora su disco :
Durante la creazione dell'indice, i file vengono scritti nella directory temporanea ($ TMPDIR su Unix,% TEMP% su Windows o il valore della variabile di configurazione --tmpdir). Ogni file temporaneo è abbastanza grande da contenere una colonna che costituisce il nuovo indice e ognuno viene rimosso non appena viene unito all'indice finale.
A causa di una limitazione di MySQL, la tabella viene copiata, anziché utilizzare la "Creazione rapida di indici" quando si crea un indice su una TABELLA TEMPORANEA. Questo è stato segnalato come MySQL Bug # 39833 .
AGGIORNAMENTO 2014-06-16 13:58 EDT
[mysqld]
datadir = /mnt/cbsvolume1/var/lib/mysql
tmpdir = /mnt/cbsvolume1/var/lib/mysql
Assicurati che /mnt/cbsvolume1/var/lib/mysql
abbia 100 G o più gratis