it-swarm-eu.dev

Wie entferne ich Fragmentierung aus InnoDB-Tabellen?

Ich habe eine Datenbank mit einer Anzahl von Tabellen.

Ich möchte einige Datensätze aus den Tabellen löschen und sagen, dass die Anzahl der Datensätze mehr als 20.000 oder 50.000 beträgt.

Alle Tabellen sind InnoDB. Und file_per_table ist aus.

Wenn ich die Datensätze aus einer Reihe von Tabellen lösche, kommt es zu einer Fragmentierung der Tabellen.

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

pdate 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.

13
Abdul Manaf

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 von OPTIMIZE TABLE Für eine in ibdata1 gespeicherte InnoDB-Tabelle führt zwei Dinge aus:

  • Macht die Daten und Indizes der Tabelle in 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

Während Sie Tabellendaten und Tabellenindizes von ibdata1 trennen und unabhängig voneinander verwalten können, verwenden Sie innodb_file_per_table , den großen klaffenden gesamten Speicherplatz in ibdata1 verschwindet einfach nicht und kann nicht zurückgefordert werden. Du musst mehr tun.

Um ibdata1 ein für alle Mal verkleinern 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) Herunterfahren von MySQL

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

Nebenbemerkung: Unabhängig von Ihrer Einstellung für innodb_buffer_pool_size stellen Sie sicher, 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 es nur das MySQL-Schema in/var/lib/mysql geben

6) Starten Sie MySQL neu

Dadurch werden ibdata1 mit 10 oder 18 MB (abhängig von der Version von MySQL), 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. Tatsächlich wird es im Laufe der Jahre sehr langsam wachsen. Der einzige Weg, wie ibdata1 schnell wächst, ist, wenn Sie eine oder mehrere der folgenden Möglichkeiten haben:

  • Viel DDL (CREATE TABLE, DROP TABLE, ALTER TABLE)
  • Viele Transaktionen
  • Pro Transaktion müssen viele Änderungen festgeschrieben werden

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, werden zwei Dateien angezeigt, die die Tabelle darstellen

  • mytable.frm (Storage Engine Header)
  • mytable.ibd (Startseite der Tabellendaten und Tabellenindizes für mydb.mytable)

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

Mit der Option innodb_file_per_table in /etc/my.cnf können Sie OPTIMIZE TABLE mydb.mytable; Ausführen, 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-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 auf lange Sicht funktionieren !!!

UPDATE 2012-04-19 09:23 EDT

Wie können Sie nach dem Ausführen der obigen Schritte bestimmen, welche Tabellen defragmentiert werden müssen? Es ist möglich, es herauszufinden, aber Sie werden es Skript haben.

Hier 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 aus ermitteln

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

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

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

Subtrahieren Sie einfach den Wert INFORMATION_SCHEMA vom Wert des Betriebssystems und dividieren Sie die Differenz durch den Wert INFORMATION_SCHEMA.

Von dort aus würden Sie entscheiden, wie viel Prozent es für notwendig 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;
14
RolandoMySQLDBA

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

Wenn Sie die Option innodb_file_per_table Nicht verwenden, können Sie nur die Datenbank exportieren und importieren. Dies ist zeit- und festplattenintensiv.

Wenn Sie jedoch innodb_file_per_table Verwenden, können Sie diesen Speicherplatz 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 ist etwas SQL, um Tabellen mit mindestens 100 MB (tatsächlich 97,65 MB) freiem Speicherplatz zu identifizieren:

SELECT Tabellenschema, Tabellenname, Tabellenkommentar 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 Spalte data_free 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' AND data_free> 100 * 1024 * 1024;

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

ALTER TABLE `TableName` ENGINE=InnoDB;

Dies ist, was MySQL hinter den Kulissen tut, wenn Sie "Tabelle optimieren" für eine 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 einer hohen Anzahl von Lösch- oder Aktualisierungsvorgängen haben, möchten Sie diese möglicherweise monatlich oder sogar wöchentlich ausführen.

5
Mahesh Patil