Speicherplatz aus InnoDB-Tabelle löschen und zurückfordern

14

Ich habe eine InnoDB-Tabelle mit 700 GB, in die ich keine Daten mehr schreibe (nur lesen). Ich möchte die älteren darin enthaltenen Daten löschen und den Speicherplatz zurückfordern (da mir der Speicherplatz ausgeht). Der Lösch-Teil ist ziemlich einfach, da ich einen Auto-Inc-Primärindex habe, mit dem ich einfach in Stücken iterieren und die Zeilen löschen kann, aber das bringt mir nicht den Platz zurück. Ich OPTIMIZE TABLEgehe davon aus , dass dies bei einem 700-GB-Tisch jedoch für immer dauern könnte. Gibt es also eine andere Option, die ich übersehen habe?

Edit von RolandoMySQLDBA

Angenommen, Ihre Tabelle ist mydb.mytable, führen Sie die folgende Abfrage aus und veröffentlichen Sie sie hier, damit Sie den für die Schrumpfung der Tabelle erforderlichen Speicherplatz bestimmen können:

SELECT
    FORMAT(dat/POWER(1024,3),2) datsize,
    FORMAT(ndx/POWER(1024,3),2) ndxsize,
    FORMAT((dat+ndx)/POWER(1024,3),2) tblsize
FROM (SELECT data_length dat,index_length ndx
FROM information_schema.tables WHERE
table_schema='mydb' AND table_name='mytable') A;

Wir müssen auch die Tabellenstruktur sehen, wenn dies erlaubt ist.

Edit von Noam

Dies ist die Ausgabe der Abfrage:

datsize ndxsize tblsize
682.51 47.57 730.08

Dies ist die Tabellenstruktur ( SHOW CREATE TABLE)

`CREATE TABLE `mybigtable` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `uid` int(11) NOT NULL,  
  `created_at` datetime NOT NULL,  
  `tid` bigint(20) NOT NULL,  
  `text` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, 
  `ft` tinyint(1) NOT NULL,  
  `irtsd` bigint(20) NOT NULL,  
  `irtuid` int(11) NOT NULL,  
  `rc` int(11) NOT NULL,  
  `r` tinyint(1) NOT NULL,  
  `e` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,  `timezone` varchar(5) NOT NULL,  PRIMARY KEY (`id`),  UNIQUE KEY `uid_tid` (`uid`,`tid`)) ENGINE=InnoDB AUTO_INCREMENT=2006963844 DEFAULT CHARSET=utf8`
Noam
quelle
Haben Sie einen anderen Datenträger, um nur die Daten abzufangen?
RolandoMySQLDBA
@RolandoMySQLDBA Ich habe eine externe Festplatte, die ich einbinden kann. Zählt das?
Noam
@RolandoMySQLDBA, aber ich hätte natürlich gerne die Option, Speicherplatz zu löschen, ohne weitere 700 GB zu benötigen
Noam
@RolandoMySQLDBA Verursacht die zusätzliche Festplattengröße Leistungsprobleme?
Aris
@Aris es kann von der Festplatte und ihrer Suchzeit abhängen. Heutzutage sind die meisten Festplatten besser in der Leistung, aber was nützt es, Zyklen zu verschwenden (auch wenn sie sehr schnell ablaufen), wenn Sie große, spärliche Plattenspeichertaschen in Ihrem Tisch haben? Dies gilt insbesondere für InnoDB, das normalerweise auf 16-KByte-Blöcke festgelegt ist. Bei einer internen Fragmentierung von 16-KByte-Blöcken möchten Sie die Tabelle möglicherweise mithilfe von defragmentieren ALTER TABLE ... ENGINE=InnoDB;(sofern Sie den Raum dazu haben). Die meisten sind nur mit ihren sehr schnellen SSDs zufrieden und würden sich keine Sorgen mehr machen.
RolandoMySQLDBA

Antworten:

21

Das ist eine gute Frage. Sie haben mehrere Lösungen, aber Ihr Tisch ist ziemlich groß, so dass keiner schmerzfrei sein wird :)

Sie haben drei Möglichkeiten, um InnoDB-Tabellen zu "verkleinern":

1. TABELLE OPTIMIEREN

Sie können verwenden, OPTIMIZE TABLEwie Sie es erwähnt haben, aber Sie sollten sich um die innodb_file_per_tableVariable kümmern :

mysql> show variables like "innodb_file_per_table";
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+
1 row in set (0.00 sec)

Lassen Sie mich erklären:

Mit OPTIMIZE TABLEInnoDB-Tabellen wird die Tabelle gesperrt, die Daten werden in eine neue saubere Tabelle kopiert (daher wird das Ergebnis verkleinert), die ursprüngliche Tabelle gelöscht und die neue Tabelle mit dem ursprünglichen Namen umbenannt. Aus diesem Grund sollten Sie darauf achten, dass das Doppelte des Volumens Ihrer Tabelle auf Ihrer Festplatte verfügbar ist (während des Betriebs benötigen Sie 2x700 GB).

Wenn Sie sich in der innodb_file_per_table = ON befinden. Alle Tabellen haben die richtige Datendatei. Die OPTIMIZEAnweisung erstellt also eine neue Datendatei (~ 700 GB), wenn der Vorgang abgeschlossen ist. MySQL löscht die ursprüngliche Datei und benennt die neue um (so dass die 700 GB - wahrscheinlich weniger, weil sie verkleinert werden - der Daten am Ende Während des Vorgangs erzeugte Daten werden freigegeben.)

Wenn Sie sich in der Tabelle innodb_file_per_table = OFF befinden. Alle Daten werden in eine Datendatei geschrieben : ibdata . Diese Datei hat eine traurige Besonderheit, sie kann nicht verkleinert werden. Während des OPTIMIZEVorgangs wird Ihre neue Tabelle erstellt (in der Nähe von 700 GB), aber auch nach dem Löschen und Umbenennen (und dem Ende der OPTIMIZEPhase) werden Ihre ibdata-Daten nicht die ~ 700 GB freigeben. Sie wollten also einige Daten freigeben, haben aber 700 GB mehr cool, nicht wahr?

2. ALTER TABLE

Sie können auch eine ALTER TABLEAnweisung verwenden, die wie ALTER TABLEfolgt funktioniert OPTIMIZE TABLE. Sie können einfach verwenden:

ALTER TABLE myTable EGINE=InnoDB;

3. ALTER TISCH (ONLINE)

Das Problem ist OPTIMIZEund ALTER TABLEdass es den Tisch während des Betriebs sperrt. Sie können das Percona-Tool verwenden: pt-online-schema-change (aus Percona Toolkit: link ). pt-online-schema ... erstellt einen Mechanismus mit Triggern und temporären Tabellen, mit denen Sie zulassen, dass die Originaltabelle während des Vorgangs zum Lesen und Schreiben zur Verfügung steht. Ich benutze dieses Tool in der Produktion für den großen, ALTERes ist ziemlich cool.

Beachten Sie, dass Sie FOREIGN KEYauf Ihre Tabelle, FK, verwiesen haben sollten und das Risiko eines Chaos auslösen. Fragen Sie Folgendes ab, um diese Voraussetzungen zu überprüfen:

mysql> SELECT COUNT(*) FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE REFERENCED_TABLE_NAME = "myTable";
+----------+
| COUNT(*) |
+----------+
|        0 |
+----------+
1 row in set (0.04 sec)

So benutze ich pt-online-schema-change:

pt-online-schema-change --alter "ENGINE=InnoDB" D=myBase,t=myTable --user --ask-pass

Beachten Sie, dass mein Hinweis zu innodb_file_per_table auch für diese Lösung zutrifft.

4. mysqldump

Die letzte Lösung besteht darin, alle Datenbanken aus einem Speicherauszug neu zu erstellen. Schrecklich lang, aber schrecklich effizient. Beachten Sie, dass dies die einzige Lösung ist, um die ibdata-Datei zu verkleinern.

Max.

Maxime Fouilleul
quelle
Außerdem benötige ich in der Option Online-Änderungstabelle des Percona-Tools 700 GB freien Speicherplatz?
Noam
Ja, pt-online benutzt nur einen Mechanismus, um das ALTER online zu machen, aber es macht trotzdem ein ALTER.
Maxime Fouilleul
@MaximeFouilleul Verursacht die zusätzliche Festplattengröße Leistungsprobleme?
Aris
1

Wenn Sie wenig Speicherplatz haben, würde ich vorschlagen, dass Sie genau wie Max mit pt-online-schema-change (ONLINE) vorschlagen. Ich war mit einem viel kleineren Tisch (200 GB) in der gleichen Situation und entschied mich, gleichzeitig eine Komprimierung durchzuführen. Etwas in dieser Richtung sollte funktionieren:

pt-online-schema-change --alter="ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4" D=myBase,t=myTable --user --ask-pass

Dies funktioniert nur, wenn Sie sich im Barracuda-Dateiformat und im COMPACT-Format der Tabelle befinden. Außerdem muss innodb_file_per_table aktiviert sein. Dies kann Wunder an der Größe Ihrer Tabelle bewirken, insbesondere wenn viel Text vorhanden ist und Sie eine kleinere KEY_BLOCK_SIZE wie 8 KB oder sogar 4 KB verwenden (die Standardeinstellung ist 16 KB). Sie können auch überprüfen, wie viel Speicherplatz Sie mit mehreren Benchmarks für dieses Problem in anderen Blogs gewinnen können. In der MySQL-Dokumentation werden jedoch 25% bis 50% (für mich waren es fast 90%) angegeben.

Beachten Sie, dass dies auch die Leistung beim Ausführen von SELECTs beeinträchtigen kann (aus der MySQL-Dokumentation):

Daher kann der Pufferpool zu einem bestimmten Zeitpunkt sowohl die komprimierte als auch die nicht komprimierte Form der Seite oder nur die komprimierte Form der Seite oder keine enthalten.

MySQL muss die Daten auch dekomprimieren, wenn sie nicht im Pufferpool sind. Seid also gewarnt.

Das hat in meinem Fall wirklich gut funktioniert. Ich hatte einen langen Text. Aus 200 GB wurden 26 GB. Aufführungen wurden nicht verändert.

Weitere Informationen finden Sie unter folgenden Links:

https://dev.mysql.com/doc/refman/5.5/de/innodb-compression-usage.html

https://dev.mysql.com/doc/refman/5.5/de/innodb-compression-internals.html

Emeric Hunter
quelle