La creazione dell'indice MySQL non riuscita sulla tabella è piena


10

AGGIORNAMENTO: tl; dr: il problema era che MySQL utilizzava TMPDIRdurante la creazione di indici. E il mio TMPDIRera quello a corto di spazio su disco.

Q originale:

Sto cercando di aggiungere un indice a una tabella InnoDB e ottengo un table is full error. Ho abbastanza spazio su disco e la configurazione di MySQL ha un file per tabella = 1. I dati della tabella sono 85 GB e suppongo che l'indice sarà di circa 20 GB - 30 GB e ho molto più spazio su disco di quello. Sto anche usando ext3, quindi non sento alcun problema con il limite della dimensione del file dal punto di vista del sistema operativo.

L'errore registrato è simile al seguente:

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

Cosa sta causando questo e come posso risolvere?

La tabella di creazione:

`CREATE TABLE `my_table` (
 `uid_from` bigint(11) NOT NULL,
 `uid_to` bigint(11) NOT NULL,
 `counter` int(11) NOT NULL,
 `updated` date NOT NULL,
 PRIMARY KEY (`uid_to`,`uid_from`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8`

Dato che i dati sono 87,4 GB e stima che ci siano circa 1,5 miliardi di righe.

SHOW GLOBAL VARIABLES LIKE 'tmpdir';
Variable_name   Value
tmpdir  /tmp

[root@web ~]# df -h /tmp
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1       40G   24G   14G  64% /

1
"InnoDB: controlla che il tuo sistema operativo e il tuo file system supportino file di queste dimensioni. InnoDB: controlla anche che il disco non sia pieno o che una quota del disco sia stata superata." - l'hai controllato? Stai usando ext2? ext3? XFS? Hai controllato le quote per l'utente?
Philᵀᴹ

@Phil Controllato entrambi. Sto usando ext3 e sono quasi sicuro che non ci sia un problema con lo spazio su disco. L'intuizione è che ha qualcosa a che fare con un registro che raggiunge il suo limite o qualcosa del genere, ma non ho davvero idea di come verificare e correggere.
Noam,

Mi chiedo quale sia il file "(unisci)"?
Akuzminsky,

@akuzminsky hmm non ne ho idea. Ho eseguito solo una nuova creazione di indice da PHPMyAdmin.
Noam,

+1 per TMPDIR, questo era anche il problema sul mio server.
Chad E.

Risposte:


8

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

Architettura di 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 fullcondizione.

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 Fullcondizioni

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_oldin 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/mysqltmpstava 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 tmpdirposizione. Se /var/lib/mysqltmpnon è 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/mysqltmpsu 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/mysqlabbia 100 G o più gratis


Mi ci sono volute settimane per costruire la tabella in primo luogo dal dump (dati da 85 GB). C'è un altro modo se non quello di ricominciare da capo? Consiglieresti forse di partizionare la tabella?
Noam,

Il partizionamento non aiuta perché ALTER TABLE per aggiungere l'indice tenterebbe comunque di caricare tutto in una singola transazione. Ricorda, stai combattendo l'architettura InnoDB, non lo spazio su disco. La mia risposta dovrebbe aiutarti in questo caso poiché mysqldump inietta alcune migliaia di righe per INSERT, non un inserimento tutto o niente in una tabella temporanea con la possibilità di un rollback.
RolandoMySQLDBA,

Ma la creazione di questa tabella richiederà (di nuovo) un'eternità. Un modo per eseguire un indice di creazione disabilitando l'opzione di rollback?
Noam,

La creazione di un indice è DDL non DML. Non è possibile modificare il comportamento DDL. Ecco perché il mio post utilizza tecniche DML.
RolandoMySQLDBA,

A proposito, quante righe ha la tabella ???
RolandoMySQLDBA,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.