Ich habe viel darüber recherchiert, wie Indizes in MySQL verwaltet werden können, um eine Fragmentierung zu verhindern und die Ausführung einiger Abfragen irgendwie zu optimieren.
Ich kenne diese Formel, die das Verhältnis zwischen dem für eine Tabelle maximal verfügbaren Speicherplatz und dem von Daten und Indizes verwendeten Speicherplatz berechnet.
Meine Hauptfragen sind jedoch noch unbeantwortet. Vielleicht liegt dies an der Tatsache, dass ich mit der Indexpflege in SQL Server vertraut bin und ich denke, dass sie in MySQL irgendwie ähnlich sein sollte.
In SQL Server können mehrere Indizes vorhanden sein, von denen jeder unterschiedliche Fragmentierungsstufen aufweisen kann. Dann können Sie eine auswählen und eine 'REORGANIZE'- oder' REBUILD'-Operation in diesem bestimmten Index ausführen, ohne den Rest zu beeinflussen.
Nach meinem besten Wissen gibt es keine "Tabellenfragmentierung" als solche, und SQL Server bietet kein Tool zum Beheben der "Tabellenfragmentierung". Es werden Tools zum Überprüfen der Indexfragmentierung (verstanden als Verhältnis zwischen der Anzahl der von einem Index verwendeten Seiten und der Fülle dieser Seite und der Kontiguität) sowie der internen und externen Fragmentierung bereitgestellt.
All das ist ziemlich einfach zu verstehen, zumindest für mich.
Wenn es darum geht, Indizes in MySQL zu verwalten, gibt es nur das oben erwähnte Konzept der Tabellenfragmentierung.
Eine Tabelle in MySQL kann mehrere Indizes haben, aber wenn ich das Fragmentierungsverhältnis mit dieser berühmten Formel überprüfe, sehe ich nicht die Fragmentierung jedes Index, sondern die Tabelle als Ganzes.
Wenn ich die Indizes in MySQL optimieren möchte, wähle ich keinen bestimmten Index für die Bearbeitung aus (wie in SQL Server). Stattdessen führe ich eine 'OPTIMIZE'-Operation in der gesamten Tabelle aus, die vermutlich alle Indizes betrifft.
Wenn die Tabelle in MySQL optimiert wird, wird das Verhältnis zwischen dem von Daten + Indizes verwendeten Speicherplatz und dem Gesamtspeicherplatz reduziert, was auf eine physische Neuorganisation der Festplatte hindeutet, was sich in einer Reduzierung des physischen Speicherplatzes niederschlägt. Bei der Indexfragmentierung geht es jedoch nicht nur um den physischen Speicherplatz, sondern auch um die Struktur des Baums, die im Laufe der Zeit aufgrund von Einfügungen und Aktualisierungen geändert wurde.
Endlich habe ich eine Tabelle in InnoDB / MySQL bekommen. Diese Tabelle enthält 3 Millionen Datensätze, 105 Spalten und 55 Indizes. Es sind 1,5 GB ohne Indizes, die 2,1 GB betragen.
Diese Tabelle wird tausende Male am Tag zum Aktualisieren und Einfügen aufgerufen (wir löschen keine Datensätze).
Diese Tabelle wurde jahrelang erstellt und ich weiß mit Sicherheit, dass niemand Indizes verwaltet.
Ich hatte erwartet, dort eine große Fragmentierung zu finden, aber wenn ich die Fragmentierungsberechnung wie vorgeschrieben durchführe
free_space / (data_length + index_length)
Es stellt sich heraus, dass ich nur eine Fragmentierung von 0,2% habe. IMHO ist das ziemlich unrealistisch.
Die großen Fragen sind also:
- Wie überprüfe ich die Fragmentierung eines bestimmten Index in MySQL, nicht der gesamten Tabelle?
- Behebt OPTIMIZE TABLE tatsächlich die interne / externe Fragmentierung eines Index wie in SQL Server?
- Wenn ich eine Tabelle in MySQL optimiere, werden dann tatsächlich alle Indizes in der Tabelle neu erstellt?
- Ist es realistisch zu glauben, dass die Reduzierung des physischen Speicherplatzes eines Index (ohne den Baum selbst neu zu erstellen) tatsächlich zu einer besseren Leistung führt?
quelle
Antworten:
Die Indexfragmentierung wird stark überbewertet. Mache dir darüber keine Sorgen.
Zwei benachbarte, etwas leere Blöcke werden von InnoDB als natürliche Verarbeitung zusammengeführt.
Durch zufällige Aktionen auf einem BTree wird es auf natürliche Weise zu durchschnittlich 69% voll. Sicher, das ist nicht 100%, aber der Aufwand für das "Reparieren" lohnt sich nicht.
SHOW TABLE STATUS
gibt Ihnen einige Metriken, aber sie sind fehlerhaft - "Data_free" enthält bestimmten "freien" Speicherplatz, aber keinen anderen "freien" Speicherplatz.In jedem Block ist nicht genutzter Speicherplatz vorhanden. freie 16KB Blöcke; freie "Extents" (nMB-Chunks); MVCC-Zeilen, die darauf warten, geerntet zu werden; Nicht-Blattknoten haben ihre eigene Fragmentierung; usw.
Percona und Oracle haben unterschiedliche Sichtweisen auf die Größe (Anzahl der Blöcke) eines Index. Ich finde keinen von ihnen wegen der begrenzten Definition von "frei" nützlich. Es scheint, dass Blöcke (jeweils 16 KB) in Blöcken (mehrere MB) zugewiesen werden, was zu der Annahme führt, dass alle Arten von Fragmentierung vorliegen. In der Realität ist es normalerweise nur der größte Teil eines dieser Multi-MB-Blöcke. Und
OPTIMIZE TABLE
macht nicht unbedingt den Raum wieder gut.Wenn SQL Server BTrees verwendet, liegt es an der Aussage, dass "keine Fragmentierung" vorliegt. Überlegen Sie, was bei einem "Block Split" passiert. Oder denken Sie an den Aufwand einer kontinuierlichen Defragmentierung. So oder so verlierst du.
Beachten Sie außerdem, dass eine Tabelle und ein Index im Wesentlichen identische Strukturen sind:
Wenn
innodb_file_per_table = ON
dies der Fall ist, können Sie die Schrumpfung (falls vorhanden) nach OPTIMIZE TABLE anhand der.ibd
Dateigröße deutlich erkennen . DennOFF
die Informationen sind vergrabenibdata1
,SHOW TABLE STATUS
können aber ziemlich genau sein, da jeder "freie" Speicherplatz zu jeder Tabelle gehört. Nun, bis auf die vorab zugewiesenen Brocken.Möglicherweise stellen Sie fest, dass eine frisch optimierte Datei pro Tabelle genau 4M, 5M, 6M oder 7M Data_free enthält. Dies ist wiederum die Vorabzuweisung und das Versäumnis, Ihnen die winzigen Details zu geben.
Ich arbeite seit über einem Jahrzehnt mit InnoDB zusammen. Ich habe mit Tausenden von großen und kleinen Tischen gearbeitet. Ich sage, dass nur ein Tisch von tausend wirklich braucht
OPTIMIZE TABLE
. Die Verwendung auf anderen Tischen ist eine Verschwendung.105 Spalten sind viel, aber vielleicht nicht zu viele.
Haben Sie 55 Indizes für eine Tabelle? Das ist schlecht. Das sind 55 Updates pro
INSERT
. Lassen Sie uns das weiter diskutieren. Denken Sie daran, dass diesINDEX(a)
nutzlos ist, wenn Sie auch habenINDEX(a,b)
. UndINDEX(flag)
ist wegen geringer Kardinalität nutzlos. (INDEX(flag, foo)
Kann aber nützlich sein.)Q1: Es gibt keine gute Möglichkeit, die Daten oder die Sekundärindizes auf alle Formen der Fragmentierung zu überprüfen.
Q2, Q3:
OPTIMIZE TABLE
Erstellt die Tabelle durchCREATEing
eine neue Tabelle undINSERTing
alle Zeilen neu, dannRENAMEing
undDROPping
. Durch das erneute Einfügen der Daten in PK-Reihenfolge wird sichergestellt, dass die Daten gut defragmentiert sind. Die Indizes sind eine andere Sache.F4: Sie könnten
DROP
undreCREATE
jeden Index bereinigen. Dies ist jedoch ein äußerst langsamer Prozess. 5.6 hat einige Beschleunigungen, aber ich weiß nicht, ob sie bei der Defragmentierung helfen.Es ist auch möglich
ALTER TABLE ... DISABLE KEYS
, dannENABLE
sie. Dies kann zu einer effizienteren Neuerstellung aller Sekundärindizes auf einmal führen.quelle
Bestehen.
Die Tabelle und ihre Indizes werden vollständig neu erstellt.
Das ist die gleiche Frage mit der gleichen Antwort.
Es ist nicht realistisch zu glauben, dass Sie den Platz reduzieren könnten, ohne den Baum neu zu erstellen. Sie gehen zusammen.
quelle
SHOW TABLE STATUS LIKE 'mytable'
würde aber einen Hinweis in derdata free
Spalte geben. dev.mysql.com/doc/refman/5.6/en/show-table-status.html