it-swarm.com.de

Die fehlgeschlagene Erstellung des MySQL-Index für die Tabelle ist voll

UPDATE: tl; dr: Das Problem war, dass MySQL beim Erstellen von Indizes das TMPDIR verwendet. Und mein TMPDIR war derjenige, dem der Speicherplatz ausgeht.

Original Q:

Ich versuche, einer InnoDB-Tabelle einen Index hinzuzufügen und ein table is full error. Ich habe genügend Speicherplatz und die MySQL-Konfiguration hat eine Datei pro Tabelle = 1. Die Tabellendaten sind 85 GB und ich gehe davon aus, dass der Index zwischen 20 GB und 30 GB liegt und ich viel mehr Speicherplatz habe. Ich verwende auch ext3, damit ich aus Sicht des Betriebssystems kein Problem mit der Dateigrößenbeschränkung habe.

Der protokollierte Fehler sieht folgendermaßen aus:

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

Was verursacht dies und wie kann ich es beheben?

Die Create-Tabelle:

`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`

Die Daten sind 87,4 GB groß und ich schätze, dass es ungefähr 1,5 Milliarden Zeilen gibt.

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

[[email protected] ~]# df -h /tmp
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1       40G   24G   14G  64% /
10
Noam

Bitte lassen Sie sich nicht von der Fehlermeldung The table 'my_table' is full Täuschen. Dieses seltene Szenario hat absolut nichts mit Speicherplatz zu tun. Dieser vollständige Zustand der Tabelle hat mit der internen Installation von InnoDB zu tun.

Schauen Sie sich zunächst dieses Diagramm der InnoDB-Architektur an

InnoDB Architecture

Bitte beachten Sie, dass der Systemtabellenbereich (die Datei ibdata) nur 128 Rollback-Segmente und 1023 Rollback-Slots pro Rollback-Segment enthält. Dadurch wird die Größe der Rollback-Kapazität einer Transaktion begrenzt. Mit anderen Worten, wenn ein einzelnes Rollback-Segment mehr als 1023 Slots benötigt, um eine Transaktion zu unterstützen, trifft die Transaktion diese table is full - Bedingung.

Denken Sie an das Restaurant Red Lobster in New Jersey . Es kann eine Kapazität von 200 Personen haben. Wenn das Restaurant voll ist, kann eine Reihe von Leuten nach draußen gehen, um zu warten. Wenn die Leute in der Leitung ungeduldig werden, können sie gehen, weil das Restaurant voll ist. Offensichtlich wäre die Lösung nicht, New Jersey größer zu machen (oder mehr Speicherplatz zu bekommen). Die Lösung wäre, das Red Lobster Restaurant größer zu machen. Auf diese Weise können Sie die Sitzplatzkapazität auf beispielsweise 240 erhöhen. Trotzdem kann sich draußen eine Linie bilden, wenn mehr als 240 Personen zu Red Lobster kommen.

Um Ihnen ein Beispiel zu geben, ich hatte einen Client mit 2 TB Systemtabellenbereich und innodb_file_per_table war deaktiviert. (346G für ibdata1, das Zurücksetzen für ibdata2). Ich habe diese Abfrage ausgeführt

SELECT SUM(data_length+index+length) InnoDBDataIndexSpace
FROM information_schema.tables WHERE engine='InnoDB';

Als nächstes habe ich InnoDBDataIndexSpace von der Summe der Dateigrößen für ibdata1 und ibdata2 abgezogen. Ich habe zwei Dinge, die mich schockierten

  • Im Systemtabellenbereich waren noch 106 GB vorhanden.
  • Ich habe die gleiche Table is Full Bedingung

Dies bedeutet, dass die 106 GB für die internen Installationen von InnoDB verwendet wurden. Der Client verwendete zu diesem Zeitpunkt ext3.

Die Lösung für mich war, ibdata3 hinzuzufügen. Ich habe dies in meinem alten Beitrag besprochen Wie löse ich "Die Tabelle ... ist voll" mit "innodb_file_per_table"?

Ich habe dies auch in anderen Beiträgen besprochen

Beachten Sie, dass diese Bedingung auch dann auftreten kann, wenn innodb_file_per_table aktiviert wurde. Wie? Rollbacks und Undo-Protokolle sind die Ursache für unkontrollierte Spitzen ist das Wachstum von ibdata1 .

IHRE TATSÄCHLICHE FRAGE

Da Sie einer Tabelle einen Index hinzufügen und Table is Full Erhalten, muss die Tabelle sehr groß sein und darf nicht in ein einzelnes Rollback-Segment passen. Sie müssen Folgendes tun:

SCHRITT 01

Holen Sie sich die Daten in eine Dump-Datei

mysqldump --no-create-info mydb mytable > table_data.sql

SCHRITT 02

Melden Sie sich bei MySQL an und führen Sie dies aus

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;

SCHRITT 03

Laden Sie die Tabelle mit dem zusätzlichen Index mit den Daten

mysql -Dmydb < table_data.sql

Das ist alles.

Das Problem ist, dass die ALTER TABLE versucht, alle Zeilen in Ihrer riesigen Tabelle als einzelne Transaktion einzufügen. Wenn Sie mysqldump verwenden, werden die Daten Tausende von Zeilen gleichzeitig in die Tabelle (jetzt mit einem neuen Index) eingefügt, nicht alle Zeilen in einer einzelnen Transaktion.

Mach dir keine Sorgen um what if this doesn't work? Die ursprüngliche Tabelle wird im Falle von irgendetwas mytable_old Genannt. Es kann als Backup dienen. Sie können die Sicherung löschen, wenn Sie wissen, dass die neue Tabelle für Sie funktioniert.

Versuche es !!!

UPDATE 2014-06-16 11:13 EDT

Wenn Sie sich Sorgen über den Speicherauszug der Daten machen, die größer sind, gzipen Sie sie einfach.

Sie können die gleichen Schritte ausführen, jedoch wie folgt

SCHRITT 01

Holen Sie sich die Daten in eine Dump-Datei

mysqldump --no-create-info mydb mytable | gzip > table_data.sql.gz

SCHRITT 02

Melden Sie sich bei MySQL an und führen Sie dies aus

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;

SCHRITT 03

Laden Sie die Tabelle mit dem zusätzlichen Index mit den Daten

gzip -d < table_data.sql.gz | mysql -Dmydb

oder

gunzip < table_data.sql.gz | mysql -Dmydb

UPDATE 2014-06-16 12:55 EDT

Ich habe gerade an einen anderen Aspekt in Bezug auf dieses Thema gedacht.

Da Sie DDL und nicht DML verwenden, ist es möglich, dass dies keine InnoDB-interne Installation ist. Da DDL kann für InnoDB nicht zurückgesetzt werden , muss das Problem eine externe Installation sein. Wo wird diese externe Installation verstopft? Ich vermute den temporären Ordner für das Betriebssystem. Warum?

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

Siehe den disk quota exceeded? Wo wird dieses Festplattenkontingent festgelegt?

Führen Sie diese Abfrage aus

SHOW GLOBAL VARIABLES LIKE 'tmpdir';

Du hast gesagt, es ist /var/lib/mysqltmp

Führen Sie dies nun im Betriebssystem aus

df -h /var/lib/mysqltmp

Etwas sagt mir, dass der Speicherplatz für /var/lib/mysqltmp Erschöpft ist. Immerhin haben Sie nur 14G frei. In den Augen der DDL (um den Index zu erstellen) kam es zu einem Rollback, nicht in der Datei ibdata1, sondern am Speicherort tmpdir. Wenn /var/lib/mysqltmp Nirgendwo gemountet ist, werden die temporären Daten in die Root-Partition geschrieben. Wenn /var/lib/mysqltmp Irgendwo gemountet ist, wird dieser Mount mit Zeilendaten gefüllt. In beiden Fällen ist nicht genügend Platz vorhanden, um die DDL abzuschließen.

Sie haben hier zwei Möglichkeiten

OPTION 1

Sie können auch eine große Festplatte erstellen (möglicherweise mit mehr als 100 GB) und /var/lib/mysqltmp Auf dieser großen Festplatte bereitstellen.

OPTION 2

Meine 3-Schritt-Vorschläge sollten auch bei begrenztem Speicherplatz funktionieren

KOMMENTAR

Es ist eine Schande, dass die von Ihnen gepostete Fehlermeldung besagt

InnoDB: Operating system error number 0.
InnoDB: Error number 0 means 'Success'.

Dies bedeutet, dass das Betriebssystem in Ordnung ist. Es gibt auch keine zugehörige Fehlernummer für diese Situation.

Es gibt noch eine andere Sache, die Sie wissen sollten. Die MySQL-Dokumentation besagt, dass die schnelle Indexerstellung für InnoDB immer noch auf der Festplatte gespeichert wird :

Während der Indexerstellung werden Dateien in das temporäre Verzeichnis geschrieben ($ TMPDIR unter Unix,% TEMP% unter Windows oder der Wert der Konfigurationsvariablen --tmpdir). Jede temporäre Datei ist groß genug, um eine Spalte zu enthalten, aus der der neue Index besteht, und jede wird entfernt, sobald sie mit dem endgültigen Index zusammengeführt wird.

Aufgrund einer Einschränkung von MySQL wird die Tabelle kopiert, anstatt "Schnelle Indexerstellung" zu verwenden, wenn Sie einen Index für eine TEMPORARY TABLE erstellen. Dies wurde als MySQL Bug # 39833 gemeldet.

UPDATE 2014-06-16 13:58 EDT

[mysqld]
datadir                         = /mnt/cbsvolume1/var/lib/mysql
tmpdir                          = /mnt/cbsvolume1/var/lib/mysql

Bitte stellen Sie sicher, dass /mnt/cbsvolume1/var/lib/mysql 100G oder mehr frei hat

8
RolandoMySQLDBA