it-swarm.com.de

So finden und reparieren Sie fragmentierte MySQL-Tabellen

Ich habe MySQLTuner verwendet, was darauf hinweist, dass einige Tabellen fragmentiert sind. ich benutzte

mysqlcheck --optimize -A

um alle Tabellen zu optimieren. Es wurden einige Tabellen repariert, aber MySQLTuner findet immer noch 19 fragmentierte Tabellen. Wie kann ich sehen, welche Tabellen defragmentiert werden müssen? Vielleicht funktioniert OPTIMIZE TABLE dort, wo mysqlcheck es nicht getan hat? Oder was soll ich sonst noch versuchen?

27
curiouscat

die kurze Antwort :

select  ENGINE, TABLE_NAME,Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free from information_schema.tables  where  DATA_FREE > 0;

Die Antwort "Sie müssen wissen"

zunächst müssen Sie verstehen, dass MySQL-Tabellen fragmentiert werden, wenn eine Zeile aktualisiert wird. Dies ist also eine normale Situation. Wenn eine Tabelle erstellt wird, beispielsweise mithilfe eines Speicherauszugs mit Daten importiert, werden alle Zeilen ohne Fragmentierung auf vielen Seiten mit fester Größe gespeichert. Wenn Sie eine Zeile mit variabler Länge aktualisieren, wird die Seite, die diese Zeile enthält, in zwei oder mehr Seiten unterteilt, um die Änderungen zu speichern, und diese neuen zwei (oder mehr) Seiten enthalten Leerzeichen, die den nicht verwendeten Bereich ausfüllen.

Dies wirkt sich nicht auf die Leistung aus, es sei denn, die Fragmentierung nimmt zu stark zu. Was zu viel Fragmentierung ist, sehen wir uns die Abfrage an, nach der Sie suchen:

  select  ENGINE, TABLE_NAME,Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free from information_schema.tables  where  DATA_FREE > 0;

DATA_LENGTH und INDEX_LENGTH sind der Speicherplatz, den Ihre Daten und Indizes verwenden, und DATA_FREE ist die Gesamtanzahl der auf allen Tabellenseiten nicht verwendeten Bytes (Fragmentierung).

Hier ist ein Beispiel für einen echten Produktionstisch

| ENGINE | TABLE_NAME               | data_length | index_length | data_free |
| InnoDB | comments                 |         896 |          316 |         5 |

In diesem Fall haben wir eine Tabelle mit (896 + 316) = 1212 MB und haben Daten mit einem freien Speicherplatz von 5 MB. Dies bedeutet ein "Fragmentierungsverhältnis" von:

5/1212 = 0.0041

... Das ist ein wirklich niedriges "Fragmentierungsverhältnis".

Ich habe mit Tabellen mit einem Verhältnis nahe 0,2 (dh 20% der Leerzeichen) gearbeitet und habe nie eine Verlangsamung der Abfragen bemerkt, selbst wenn ich die Tabelle optimiere, ist die Leistung dieselbe. Das Anwenden einer Optimierungstabelle auf eine 800-MB-Tabelle nimmt jedoch viel Zeit in Anspruch und blockiert die Tabelle für einige Minuten, was für die Produktion nicht praktikabel ist.

Wenn Sie also überlegen, was Sie an Leistung gewinnen und wie viel Zeit für die Optimierung einer Tabelle verschwendet wird, bevorzuge ich NICHT OPTIMIEREN.

Wenn Sie der Meinung sind, dass es für die Speicherung besser ist, sehen Sie sich Ihr Verhältnis an und sehen Sie, wie viel Speicherplatz Sie bei der Optimierung sparen können. Es ist normalerweise nicht zu viel, deshalb bevorzuge ich NICHT OPTIMIEREN.

Wenn Sie optimieren, werden beim nächsten Update Leerzeichen erstellt, indem eine Seite in zwei oder mehr geteilt wird. Das Aktualisieren einer fragmentierten Tabelle ist jedoch schneller als das Aktualisieren einer nicht fragmentierten Tabelle, da bei einer Fragmentierung der Tabelle eine Aktualisierung einer Zeile nicht unbedingt eine Seite aufteilt.

Ich hoffe das hilft dir.

38
Felipe Rojas

Um die Antwort von Felipe-Rojas zu ergänzen, können Sie das Fragmentverhältnis als Teil der Abfrage berechnen:

select ENGINE,
  concat(TABLE_SCHEMA, '.', TABLE_NAME) as table_name,
  round(DATA_LENGTH/1024/1024, 2) as data_length,
  round(INDEX_LENGTH/1024/1024, 2) as index_length,
  round(DATA_FREE/1024/1024, 2) as data_free,
  (data_free/(index_length+data_length)) as frag_ratio
FROM information_schema.tables
WHERE DATA_FREE > 0
ORDER BY frag_ratio DESC;

Wenn eine Tabelle zu einem kleinen Prozentsatz fragmentiert ist (weniger als 5%?), Können Sie sie wahrscheinlich in Ruhe lassen.

Alles, was größer ist, und Sie müssen anhand Ihrer Datenbanknutzung, Sperrtabellen usw. beurteilen, wie wichtig es ist, die Tabelle zu defragmentieren.

15
sysadmiral

"Tabelle optimieren" behebt tatsächlich das Problem, das Sie haben.

Wenn Sie nur wenige Datenbanken haben, können Sie mit PHPMyAdmin alle Ihre Datenbanken durchsuchen. Wählen Sie die Tabellen mit Overhead aus und wählen Sie dann zur Optimierung aus.

Wenn Sie viele Datenbanken haben, ist wahrscheinlich eine andere Methode vorzuziehen.

Ich verwende das folgende PHP Skript-Setup in Cron, um jede Stunde auszuführen.

$DB = new mysqli ('localhost', 'DbUser', 'DbPassword');
$results = $DB->query('show databases');
$allDbs = array();
while ($row = $results->fetch_array(MYSQLI_NUM))
{
    $allDbs[] = $row[0];
}
$results->close();
foreach ($allDbs as $dbName)
{
    if ($dbName != 'information_schema' && $dbName != 'mysql')
    {
        $DB->select_db($dbName);
        $results = $DB->query('SHOW TABLE STATUS WHERE Data_free > 0');
        if ($results->num_rows > 0)
        {
            while ($row = $results->fetch_assoc())
            {
                $DB->query('optimize table ' . $row['Name']);
            }
        }
        $results->close();
    }
}
$DB->close();
2
Daemon of Chaos

Ich bin auf diese Seite gestoßen und fand die Fragen von Felipe-Rojas und Sysadmiral sehr hilfreich. In meinem Fall habe ich die Abfrage in phpMyAdmin von WHM ausgeführt und nur TABLE_NAME zu erhalten war nicht so hilfreich, da die Datenbank nicht aufgelistet war und mehrere Datenbanken dieselben Tabellennamen haben. Fügen Sie einfach TABLE_SCHEMA wird auch diese Spalte bereitstellen.

select  ENGINE, TABLE_SCHEMA, TABLE_NAME, Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free, (data_free/(index_length+data_length)) as frag_ratio from information_schema.tables  where  DATA_FREE > 0 order by frag_ratio desc

Zeigt DB an

ENGINE  | TABLE_SCHEMA  | TABLE_NAME    | data_length   | index_length  | data_free | frag_ratio

InnoDB  | db_name       | db_table      | 0             | 0             | 8         | 170.6667

Um das Problem zu beheben, habe ich den Link Defragmentierungstabelle in phpMyAdmin für jede der Tabellen verwendet, die zu einem hohen "frag_ratio" geführt haben, für das phpMyAdmin ausgeführt wird:

ALTER TABLE `table_name` ENGINE = InnoDB;
2
Chris

Eine Tabelle, die die InnoDB Engine von MySQL verwendet, muss im Wesentlichen niemals OPTIMIZEd sein.

Der Wert von Data_free Aus information_schema.tables Oder SHOW TABLE STATUS Ist sehr oft ungleich Null, selbst wenn Sie glauben, alles getan zu haben, was Sie tun können, um Ihre Tabelle (n) zu defragmentieren. Darüber hinaus ist diese Metrik nur eine von mehreren Fragmentierungen, die auftreten können und müssen. (Verschwendeter Speicherplatz in Blöcken, Rückgängigmachen von Listen, Index-BTrees im Vergleich zu Daten-BTrees usw. usw.

Und innodb_file_per_table Erschwert die Verwendung von Data_free. Wenn sich die Tabelle in ibdata1 Befindet, bezieht sich Data_free Auf den gesamten Tabellenbereich. eine ziemlich nutzlose Zahl. Wenn sich die Tabelle in einer eigenen .ibd - Datei befindet, sind es wahrscheinlich einige MB oder einige Prozent der Tabellengröße, je nachdem, welcher Wert größer ist.

Nur wenn Sie viele von Zeilen nd gelöscht haben, beabsichtigen Sie nicht, die Tabelle wieder aufzufüllen, möglicherweise es lohnt sich, OPTIMIZE TABLE Auszuführen. .

PARTITIONs zeigt auch eine störende Menge von Data_free an, da jede Partition normalerweise 4-7 MB "frei" anzeigt. Und das wird nicht verschwinden.

Warum Defragmentierung?

  • Speicherplatz an das Betriebssystem zurückgeben? Nun, Sie könnten dies kurz erreichen, wenn Sie innodb_file_per_table=1 Hatten. Wenn Sie jedoch Zeilen hinzufügen, nehmen Sie diese vom Betriebssystem zurück.
  • Um den Zugang zu beschleunigen? Vergiss es. Das Layout der Blöcke auf der Festplatte ist relativ zufällig und seit einigen Jahrzehnten. Vor einem halben Jahrhundert war es etwas wichtig, Blöcke neu anzuordnen.
  • BTrees neu ausbalancieren? Damit? Sie werden sofort wieder aus dem Gleichgewicht geraten. Der stationäre Zustand für BTrees, in die zufällig eingefügt wird, beträgt 69%. Und das wird nicht einmal in Data_free Berücksichtigt.
  • MySQLTuner sagt zu? Das Produkt muss abkühlen.

Eine Geschichtsnotiz. Als ich DBAs hauptsächlich mit MyISAM-Tabellen half, entdeckte ich vielleicht 2 von 1000 Tabellen, denen ein monatlichOPTIMIZE half. Seitdem habe ich mit Tausenden von InnoDB-Tabellen gearbeitet und noch ein Leistungsproblem gefunden, das wahrscheinlich durch OPTIMIZE behoben wurde. (Sicher, es gab Speicherplatzprobleme, bei denen OPTIMIZE helfen könnte, aber das wird schwierig - normalerweise verfügt der DBA nicht über genügend Speicherplatz, um OPTIMIZE auszuführen!)

1
Rick James