Wie entferne ich Fragmentierung aus InnoDB-Tabellen?

13

Ich habe eine Datenbank mit einer Anzahl von Tabellen.

Ich möchte einige Datensätze aus den Tabellen löschen, wenn die Anzahl der Datensätze mehr als 20 KB oder 50 KB beträgt.

Alle Tabellen sind InnoDB. Und file_per_tableist aus .

Wenn ich die Datensätze aus einer Reihe von Tabellen lösche, werden die Tabellen fragmentiert.

Gibt es eine Möglichkeit, die Fragmentierung zu entfernen?

Update am 17. April

mysql> select TABLE_NAME, TABLE_SCHEMA, Data_free from information_schema.TABLES where TABLE_SCHEMA NOT IN ('information_schema', 'mysql') and Data_Free >0;
+-----------------+--------------+-----------+
| TABLE_NAME      | TABLE_SCHEMA | Data_free |
+-----------------+--------------+-----------+
| City            | world_innodb |   5242880 |
| City_Copy       | world_innodb |   5242880 |
| Country         | world_innodb |   5242880 |
| CountryLanguage | world_innodb |   5242880 |
| a               | world_innodb |   5242880 |
| t1              | world_innodb |   5242880 |
| t2              | world_innodb |   5242880 |
+-----------------+--------------+-----------+
7 rows in set (0.00 sec)

Nun ist meine Frage, wie ich entscheiden werde, ob meine Tabellen fragmentiert sind oder nicht.

Abdul Manaf
quelle
1
Und ein Artikel InnoDB: Achten Sie auf die Fragmentierung von Perconas Blog-Site.
Ypercubeᵀᴹ

Antworten:

14

Ich habe dies bereits im Oktober 2010 in StackOverflow angesprochen .

Beachten Sie die am stärksten ausgelastete Datei in der InnoDB-Infrastruktur: / var / lib / mysql / ibdata1

Diese Datei enthält normalerweise vier Arten von Informationen

  • Tabellendaten
  • Tabellenindizes
  • MVCC-Daten (Multiversioning Concurrency Control)
  • Tabellenmetadaten (Liste der Tablespace-IDs)

Das Ausführen OPTIMIZE TABLEgegen eine in ibdata1 gespeicherte InnoDB-Tabelle bewirkt zwei Dinge:

  • Macht die Daten und Indizes der Tabelle innerhalb von ibdata1 zusammenhängend und ermöglicht so einen schnelleren Zugriff
  • Dadurch wächst ibdata1, da die zusammenhängenden Daten und Indexseiten an ibdata1 angehängt werden

Sie können Tabellendaten und Tabellenindizes von ibdata1 trennen und sie unabhängig mit innodb_file_per_table verwalten , wird der große klaffende gesamte Speicherplatz in ibdata1 einfach nicht verschwinden und kann nicht zurückgefordert werden. Du musst mehr tun.

Um zu schrumpfen ibdata1 ein für alle Mal , müssen Sie Folgendes tun:

1) MySQLDump alle Datenbanken in eine SQL-Textdatei (nennen Sie es /root/SQLData.sql)

2) Löschen Sie alle Datenbanken (außer MySQL-Schema)

3) Fahren Sie mysql herunter

4) Fügen Sie die folgenden Zeilen zu /etc/my.cnf hinzu

[mysqld]
innodb_file_per_table
innodb_flush_method=O_DIRECT
innodb_log_file_size=1G
innodb_buffer_pool_size=4G

Anmerkung: Unabhängig von Ihrer Einstellung für innodb_buffer_pool_size müssen Sie sicherstellen, dass innodb_log_file_size 25% von innodb_buffer_pool_size beträgt.

5) Löschen Sie ibdata1, ib_logfile0 und ib_logfile1

Zu diesem Zeitpunkt sollte nur das MySQL-Schema in / var / lib / mysql vorhanden sein

6) Starten Sie mysql neu

Dadurch wird ibdata1 mit 10 oder 18 MB (je nach MySQL-Version), ib_logfile0 und ib_logfile1 mit jeweils 1 GB neu erstellt

7) Laden Sie /root/SQLData.sql neu in mysql

ibdata1 wächst, enthält jedoch nur Tabellenmetadaten. In der Tat wird es im Laufe der Jahre sehr langsam wachsen. Der einzige Weg, wie ibdata1 schnell wachsen kann, ist, wenn Sie eine oder mehrere der folgenden Möglichkeiten haben:

  • Viele DDL ( CREATE TABLE, DROP TABLE, ALTER TABLE)
  • Viele Transaktionen
  • Viele Änderungen, die pro Transaktion festgeschrieben werden müssen

Jede InnoDB-Tabelle existiert außerhalb von ibdata1

Angenommen, Sie haben eine InnoDB-Tabelle mit dem Namen mydb.mytable. Wenn Sie in / var / lib / mysql / mydb gehen, sehen Sie zwei Dateien, die die Tabelle darstellen

  • mytable.frm (Speicher-Engine-Header)
  • mytable.ibd (Heimat von Tabellendaten und Tabellenindizes für mydb.mytable)

ibdata1 enthält nie mehr InnoDB-Daten und -Indizes.

Mit der Option innodb_file_per_table in /etc/my.cnf können Sie ausführen OPTIMIZE TABLE mydb.mytable; und die Datei /var/lib/mysql/mydb/mytable.ibd wird tatsächlich verkleinert.

Ich habe dies in meiner Karriere als MySQL-DBA viele Male getan

Tatsächlich habe ich beim ersten Mal eine 50 GB große ibdata1-Datei auf 500 MB reduziert.

Versuche es. Wenn Sie weitere Fragen dazu haben, senden Sie mir eine E-Mail. Vertrau mir. Dies wird kurzfristig und langfristig funktionieren !!!

UPDATE 19.04.2012 09:23 EDT

Wie können Sie ermitteln, welche Tabellen defragmentiert werden müssen, nachdem Sie die obigen Schritte ausgeführt haben? Es ist möglich, es herauszufinden, aber Sie werden es als Skript haben.

Hier ist ein Beispiel: Angenommen, Sie haben die Tabelle mydb.mytable. Wenn innodb_file_per_table aktiviert ist, haben Sie die Datei /var/lib/mysql/mydb/mytable.ibd

Sie müssen zwei Nummern abrufen

FILESIZE FROM OS: So können Sie die Dateigröße vom Betriebssystem ermitteln

ls -l /var/lib/mysql/mydb/mytable.ibd | awk '{print $5}'

FILESIZE FROM INFORMATION_SCHEMA: Sie können die Dateigröße wie folgt aus information_schema.tables ermitteln:

SELECT (data_length+index_length) tblsize FROM information_schema.tables
WHERE table_schema='mydb' AND table_name='mytable';

Subtrahieren Sie einfach den INFORMATION_SCHEMA-Wert vom OS-Wert und dividieren Sie die Differenz durch den INFORMATION_SCHEMA-Wert.

Von dort aus würden Sie entscheiden, wie viel Prozent es für erforderlich halten, diese Tabelle zu defragmentieren. Natürlich defragmentieren Sie es mit einem der folgenden Befehle:

OPTIMIZE TABLE mydb.mytable;

oder

ALTER TABLE mydb.mytable ENGINE=InnoDB;
RolandoMySQLDBA
quelle
Ich glaube nicht, dass / var / lib / mysql / ibdata1 sehr beschäftigt ist, wenn Sie die empfohlene Option innodb_file_per_table = 1 verwenden
CrackerJack9
1
@ CrackerJack9 ibdata1 ist aufgrund dessen, was darin steckt, unglaublich hervorragend: 1) Informationen zum doppelten Schreibpuffer, 2) Puffer für Sekundärindizes einfügen, 3) Datenwörterbuch, 4) Rollback-Segmente, 5) Tablespace rückgängig machen. Bitte gehen Sie zu scribd.com/doc/31337494/XtraDB-InnoDB-internals-in-drawing, um eine bildliche Darstellung dieser Dinge zu erhalten. Selbst wenn Daten und Indexseiten für InnoDB-Tabellen entfernt werden, kann ibdata1 in einer Umgebung mit hohen Transaktionsraten immer noch erheblich wachsen.
RolandoMySQLDBA
1
@ CrackerJack9 Ich habe einen zusätzlichen Beitrag über die zusätzlichen Aktivitäten rund um ibdata1: dba.stackexchange.com/a/23367/877
RolandoMySQLDBA
Ich hatte nicht bemerkt, dass es immer noch so stark genutzt wurde. Sehr geschätzt!
CrackerJack9
@RolandoMySQLDBA Kannst du dich auf den Heap begeben, wenn du Zeit hast?
Ypercubeᵀᴹ
5

Wenn Sie häufig Zeilen löschen (oder Zeilen mit Datentypen variabler Länge aktualisieren), wird möglicherweise viel Speicherplatz in den Datendateien verschwendet, ähnlich wie bei der Fragmentierung des Dateisystems.

Wenn Sie diese innodb_file_per_tableOption nicht verwenden , können Sie lediglich die Datenbank exportieren und importieren. Dies ist eine zeit- und festplattenintensive Prozedur.

Aber wenn Sie verwenden innodb_file_per_table, können Sie diesen Platz identifizieren und zurückfordern!

Vor 5.1.21 ist der Zähler für freien Speicherplatz in der Spalte table_comment von information_schema.tables verfügbar. Hier einige SQL-Anweisungen zum Identifizieren von Tabellen mit mindestens 100 MB (tatsächlich 97,65 MB) freiem Speicherplatz:

SELECT table_schema, table_name, table_comment FROM
information_schema.tables WHERE ENGINE LIKE 'InnoDB' UND table_comment RLIKE 'InnoDB free: ([0-9] {6,}). *';

Ab 5.1.21 wurde dies in die data_free-Spalte verschoben (ein viel geeigneterer Ort):

SELECT table_schema, table_name, data_free / 1024/1024 AS data_free_MB FROM information_schema.tables WHERE ENGINE LIKE 'InnoDB' UND data_free> 100 * 1024 * 1024;

Sie können den verlorenen Speicherplatz zurückfordern, indem Sie die Tabelle neu erstellen. Der beste Weg, dies zu tun, ist die Verwendung von 'alter table', ohne etwas zu ändern:

ALTER TABLE `TableName` ENGINE=InnoDB;

Dies ist, was MySQL hinter den Kulissen macht, wenn Sie 'Optimize Table' auf einer InnoDB-Tabelle ausführen. Dies führt zu einer Lesesperre, jedoch nicht zu einer vollständigen Tabellensperre. Wie lange es dauert, hängt vollständig von der Datenmenge in der Tabelle ab (jedoch nicht von der Größe der Datendatei). Wenn Sie eine Tabelle mit vielen Lösch- oder Aktualisierungsvorgängen haben, können Sie diese monatlich oder sogar wöchentlich ausführen.

Mahesh Patil
quelle
Eine weitere Sache, die ich nicht verstehen kann, was data_free> 100 * 1024 * 1024 bedeutet. Und als ich das Ergebnis sah, kann ich nicht entscheiden, ob die Tabelle fragmentiert ist oder nicht kann sagen, die Tabelle ist fragmentiert oder nicht fragmentiert.
Abdul Manaf
Schauen Sie sich den Teil "Mein Update" an.
Abdul Manaf