Kapitel 8. MySQL-Tabellentypen

Inhaltsverzeichnis

8.1. MyISAM-Tabellen
8.1.1. Für Schlüssel benötigter Speicherplatz
8.1.2. MyISAM-Tabellenformate
8.1.3. MyISAM-Tabellenprobleme
8.2. MERGE-Tabellen
8.2.1. MERGE-Tabellenprobleme.
8.3. ISAM-Tabellen
8.4. HEAP-Tabellen
8.5. InnoDB-Tabellen
8.5.1. Überblick über InnoDB-Tabellen
8.5.2. Mit InnoDB anfangen - Optionen
8.5.3. InnoDB-Tabellenplatz (Tablespace) erzeugen
8.5.4. InnoDB-Tabellen erzeugen
8.5.5. Hinzufügen und Entfernen von InnoDB-Daten- und -Log-Dateien
8.5.6. Datensicherung und Wiederherstellung einer InnoDB-Datenbank
8.5.7. Eine InnoDB-Datenbank auf eine andere Maschine verschieben
8.5.8. InnoDB-Transaktionsmodell
8.5.9. Tipps zur Performance-Steigerung
8.5.10. Implementation des Multiversionings
8.5.11. Tabellen- und Index-Strukturen
8.5.12. Verwaltung von Datei-Speicherplatz und Festplatten-Eingaben / -Ausgaben
8.5.13. Fehlerbehandlung
8.5.14. Beschränkungen von InnoDB-Tabellen
8.5.15. InnoDB-Kontaktinformationen
8.6. BDB- oder Berkeley_db-Tabellen
8.6.1. Überblick über BDB-Tabellen
8.6.2. BDB installieren
8.6.3. BDB-Startoptionen
8.6.4. Kennzeichen von BDB-Tabellen
8.6.5. Was in naher Zukunft bei BDB in Ordnung gebracht werden muss
8.6.6. Betriebssysteme, die von BDB unterstützt werden
8.6.7. Fehler, die bei der Benutzung von BDB-Tabellen auftreten können

AB MySQL-Version 3.23.6 können Sie unter drei grundlegenden Tabellenformaten (ISAM, HEAP und MyISAM wählen. Neuere MySQL-Versionen können zusätzliche Tabellentypen unterstützen (InnoDB, oder BDB), abhängig davon, wie Sie sie kompilieren.

Beim Erzeugen einer neuen Tabelle können Sie MySQL mitteilen, welcher Tabellentyp dafür benutzt werden soll. MySQL erzeugt immer eine .frm-Datei, die die Tabellen- und Spaltendefinitionen enthält. Abhängig vom Tabellentyp werden Index und Daten in anderen Dateien gespeichert.

Beachten Sie, dass Sie für die Benutzung von InnoDB-Tabellen zumindest die innodb_data_file_path-Startoption benötigen. See Abschnitt 8.5.2, „Mit InnoDB anfangen - Optionen“.

Der vorgabemäßige Tabellentyp in MySQL ist MyISAM. Wenn Sie versuchen, einen Tabellentyp zu benutzen, der nicht einkompiliert oder aktiviert ist, erzeugt MySQL statt dessen eine Tabelle vom Typ MyISAM. Das ist ein sehr nützliches Feature, wenn Sie Tabellen zwischen unterschiedlichen SQL-Servern kopieren wollen, die unterschiedliche Tabellentypen unterstützten (zum Beispiel Tabellen zu einem Slave kopieren, der für Geschwindigkeit optimiert ist, aber keine transaktionalen Tabellen hat). Dieses automatische Ändern des Tabellentyps kann andererseits für neue MySQL-Benutzer sehr verwirrend sein. Wir planen für MySQL 4.0, das zu beheben, indem eine Warnung ausgegeben wird, wenn ein Tabellentyp automatisch geändert wird.

Sie können Tabellen zwischen unterschiedlichen Typen mit dem ALTER TABLE-Statement umwandeln. See Abschnitt 7.5.4, „ALTER TABLE-Syntax“.

MySQL unterstützt zwei unterschiedliche Arten von Tabellen: transaktionssichere Tabellen (InnoDB und BDB) und nicht transaktionssichere Tabellen (HEAP, ISAM, MERGE und MyISAM).

Vorteile transaktionssicherer Tabellen (TST):

Vorteile nicht transaktionssicherer Tabellen (NTST):

Sie können TST- and NTST-Tabellen in denselben Statements kombinieren, um das Beste aus beiden Welten zu bekommen.

8.1. MyISAM-Tabellen

MyISAM ist der vorgabemäßige Tabellentyp in MySQL-Version 3.23. Er basiert auf dem ISAM-Code und hat viele nützliche Erweiterungen.

Der Index wird in einer Datei mit der Endung .MYI (MYIndex) gespeichert, die Daten in einer Datei mit der Endung .MYD (MYData). Sie können MyISAM-Tabellen mit dem myisamchk-Dienstprogramm überprüfen und reparieren. See Abschnitt 5.4.6.9, „Wie Tabellen repariert werden“. Sie können MyISAM-Tabellen mit myisampack komprimieren, damit sie viel weniger Speicherplatz benötigen. See Abschnitt 5.7.4, „myisampack, MySQL-Programm zum Erzeugen komprimierter Nur-Lese-Tabellen“.

Folgende Neuerungen gibt es bei MyISAM:

  • Es gibt einen Flag in der MyISAM-Datei, der anzeigt, ob die Tabelle korrekt geschlossen wurde. Wenn mysqld mit --myisam-recover gestartet wird, werden MyISAM-Tabellen beim Öffnen automatisch geprüft und / oder repariert, falls die Tabelle nicht korrekt geschlossen wurde.

  • Sie können neue Zeilen in eine Tabelle, die keinerlei freie Blöcke mitten in der Daten-Datei hat, einfügen (INSERT), während zeitgleich andere Threads aus der Tabelle lesen (zeitgleiches Einfügen). Ein freier Block kann entstehen, wenn eine Aktualisierung einer Zeile dynamischer Länge, die viele Daten enthält, mit weniger Daten durchgeführt wird, oder wenn Zeilen gelöscht werden. Wenn alle freien Blöcke aufgebraucht sind, können alle zukünftigen Einfügeoperationen auf die zeitgleiche Art erfolgen.

  • Unterstützung für große Dateien (63-Bit) auf Dateisystemen / Betriebssystemen, die große Dateien unterstützen.

  • Alle Daten werden mit dem niedrigen Byte zuerst gespeichert. Das macht die Daten Maschinen- und Betriebssystem-unabhängig. Die einzige Anforderung ist, dass die Maschine zweien-komplementäre vorzeichenbehaftete Ganzzahlen (two's-complement signed integers) benutzt, was bei jeder Maschine in den letzten 20 Jahren der Fall war), sowie das IEEE-Fließkomma-Format (bei Mainstream-Maschinen absolut dominierend). Die einzige Art von Maschinen, die vielleicht keine Binärkompatibilität unterstützen, sind eingebettete Systeme (Embedded Systems), weil diese manchmal eigentümliche Prozessoren haben.

    Wenn Daten mit dem niedrigen Byte zuerst gespeichert werden, ergibt sich daraus kein großer Geschwindigkeitsnachteil. Die Bytes in einer Tabellenzeile sind normalerweise unzusammenhängend und man benötigt kaum mehr Ressourcen, um ein unzusammenhängendes Byte in Reihenfolge statt in umgekehrter Reihenfolge zu lesen. Der tatsächliche Hole-Spaltenwert-Code ist im Vergleich zu sonstigem Code ebenfalls nicht zeitkritisch.

  • Alle Zahlenschlüssel werden mit dem hohen Byte zuerst gespeichert, um bessere Index-Kompression zu erzielen.

  • Die interne Handhabung einer AUTO_INCREMENT-Spalte. MyISAM aktualisiert diese automatisch bei INSERT / UPDATE. Der AUTO_INCREMENT-Wert kann mit myisamchk zurückgesetzt werden. Das macht AUTO_INCREMENT-Spalten schneller (mindestens 10%), und alten Zahlen werden im Gegensatz zum alten ISAM nicht wieder benutzt. Beachten Sie, dass das alte Verhalten immer noch da ist, wenn ein AUTO_INCREMENT am Ende eines mehrteiligen Schlüssels definiert wird.

  • Wenn er in sortierter Reihenfolge eingefügt wird (wie bei der Benutzung einer AUTO_INCREMENT-Spalte), wird der Schlüsselbaum gespalten, so dass der hohe Knoten nur einen Schlüssel enthält. Das verbessert die Platzausnutzung im Schlüsselbaum.

  • BLOB- und TEXT-Spalten können indiziert werden.

  • NULL-Werte sind in indizierten Spalten erlaubt. Dafür werden 0 bis 1 Byte pro Schlüssel benötigt.

  • Die maximale Schlüssellänge beträgt vorgabemäßig 500 Bytes (das kann beim Neukompilieren geändert werden). Wenn Schlüssel länger als 250 Bytes sind, wird für diese eine höhere Schlüsselblockgröße als die vorgabemäßigen 1024 Bytes benutzt.

  • Die maximale Anzahl von Schlüsseln pro Tabelle beträgt vorgabemäßig 32. Diese kann bis auf 64 erhöht werden, ohne dass myisamchk neu kompiliert werden muss.

  • myisamchk kennzeichnet Tabellen als geprüft, wenn es mit --update-state läuft. myisamchk --fast prüft nur die Tabellen, die diese Kennzeichnung nicht haben.

  • myisamchk -a speichert Statistiken für Schlüsselteile (und nicht nur für gesamte Schlüssel wie bei ISAM).

  • Zeilen dynamischer Größe werden viel weniger fragmentiert werden, wenn Lösch- mit Aktualisierungs- und Einfügeoperationen gemischt werden. Dafür wird gesorgt, indem angrenzende gelöschte Blöcke automatisch kombiniert werden und dadurch, dass Blöcke erweitert werden, wenn der nächste Block gelöscht wird.

  • myisampack kann BLOB- and VARCHAR-Spalten komprimieren.

  • Sie können die Daten-Datei und die Index-Datei in unterschiedliche Verzeichnisse legen, um mehr Geschwindigkeit zu erhalten (mit der DATA/INDEX DIRECTORY="pfad"-Option für CREATE TABLE). See Abschnitt 7.5.3, „CREATE TABLE-Syntax“.

MyISAM unterstützt ausserdem die folgenden Dinge, die MySQL in naher Zukunft benutzen können wird:

  • Unterstützung für einen echten VARCHAR-Typ. Eine VARCHAR-Spalte fängt mit einer in 2 Bytes gespeicherten Länge an.

  • Tabellen mit VARCHAR können eine feste oder dynamische Datensatzlänge haben.

  • VARCHAR und CHAR können bis zu 64 KB Groß sein. Alle Schlüsselsegmente haben ihre eigene Sprachdefinition. Das versetzt MySQL in die Lage, unterschiedliche Sprachdefinitionen pro Spalte zu haben.

  • Ein gehashter berechneter Index kann für UNIQUE benutzt werden. Das erlaubt Ihnen, UNIQUE auf jeder beliebigen Kombination von Spalten in einer Tabelle zu haben. (Sie können jedoch auf einem UNIQUE berechneten Index nicht suchen.)

Beachten Sie, dass Index-Dateien bei MyISAM üblicherweise viel kleiner sind als bei ISAM. Das bedeutet, dass MyISAM normalerweise weniger Systemressourcen verbraucht als ISAM, allerdings mehr Prozessorleistung beim Einfügen von Daten in einen komprimierten Index.

Folgende Optionen für mysqld können benutzt werden, um das Verhalten von MyISAM-Tabellen zu ändern. See Abschnitt 5.5.5.4, „SHOW VARIABLES.

OptionBeschreibung
--myisam-recover=#Automatische Wiederherstellung beschädigter Tabellen.
-O myisam_sort_buffer_size=#Der beim Wiederherstellen von Tabellen benutzte Puffer.
--delay-key-write-for-all-tablesKeine Schlüsselpuffer zwischen Schreibvorgängen auf jedwede MyISAM-Tabelle zurückschreiben (flush).
-O myisam_max_extra_sort_file_size=#Wird benutzt, um MySQL bei der Entscheidung zu helfen, wann die langsame, aber sichere Schlüssel-Cache-Index-Erzeugungsmethode benutzt werden sollte. Hinweis: Dieser Parameter wird in Megabytes angegeben!
-O myisam_max_sort_file_size=#Die schnelle Index-Sortiermethode beim Erzeugen eines Indexes nicht benutzen, wenn die temporäre Datei größer als dieser Wert werden würde. Hinweis: Dieser Parameter wird in Megabytes angegeben! megabytes!--
-O myisam_bulk_insert_tree_size=#Die Größe des Baum-Caches, der bei der Optimierung von Massen-Einfügeoperationen benutzt wird. Hinweis: Das ist die Begrenzung pro Thread!

Die automatische Wiederherstellung wird aktiviert, wenn Sie mysqld mit --myisam-recover=# starten. See Abschnitt 5.1.1, „mysqld-Kommandozeilenoptionen“. Beim Öffnen wird geprüft, ob die Tabelle als beschädigt gekennzeichnet ist oder ob die Zählvariable für die Tabelle nicht 0 ist und Sie mit --skip-locking laufen lassen. Wenn eine dieser Bedingungen erfüllt ist, geschieht folgendes:

  • Die Tabelle wird auf Fehler geprüft.

  • Wenn ein Fehler gefunden wird, wird eine schnelle Reparatur der Tabelle versucht (mit Sortieren und ohne Neuerzeugung der Daten-Datei).

  • Wenn die Reparatur wegen eines Fehlers in der Daten-Datei fehlschlägt (zum Beispiel ein Fehler wegen eines doppelten Schlüsseleintrags), wird die Reparatur noch einmal versucht, diesmal allerdings mit Neuerzeugung der Daten-Datei.

  • Wenn dieser Versuch fehlschlägt, wird die Reparatur noch einmal mit der alten Reparaturoption versucht (Zeile für Zeile ohne Sortieren schreiben), was jede Sorte von Fehler beheben sollte, bei gewissen Festplatten-Erfordernissen ...

Wenn die Wiederherstellung nicht in der Lage ist, alle Zeilen aus einem vorher abgeschlossenen Statement wiederherzustellen, und Sie nicht FORCE als Option für myisam-recover angegeben haben, wird die automatische Reparatur mit einer Fehlermeldung in der Fehlerdatei abgebrochen:

Error: Couldn't repair table: test.g00pages

Hätten Sie in diesem Fall die FORCE-Option benutzt, würden Sie statt dessen in der Fehlerdatei eine Warnung erhalten:

Warning: Found 344 of 354 rows when repairing ./test/g00pages

Wenn Sie automatisches Wiederherstellung mit der BACKUP-Option laufen lassen, beachten Sie, dass Sie ein Cron-Skript haben sollten, dass automatisch Dateien mit Namen wie tabellenname-datetime.BAK aus den Datenbank-Verzeichnissen auf ein Sicherungsmedium verschiebt.

See Abschnitt 5.1.1, „mysqld-Kommandozeilenoptionen“.

8.1.1. Für Schlüssel benötigter Speicherplatz

MySQL unterstützt unterschiedliche Index-Typen, doch der normale Typ ist ISAM oder MyISAM. Diese benutzen einen B-Baum-Index, und Sie können die Größe der Index-Datei grob als (schluessel_laenge+4)/0.67 kalkuliert, summiert über alle Schlüssel. (Das ist der schlechteste Fall, bei dem alle Schlüssel in sortierter Reihenfolge eingeordnet werden und es keinerlei Schlüssel-Komprimierung gibt.)

Zeichenketten-Indexe werden Leerzeichen-komprimiert. Wenn der erste Index-Teil eine Zeichenkette ist, wird er zusätzlich Präfix-komprimiert. Leerzeichen-Kompression macht die Index-Datei kleiner als in den obigen Zahlen dargestellt, wenn die Zeichenkettenspalte viele Leerzeichen am Ende hat oder eine VARCHAR-Spalte ist, die nicht immer in voller Länge genutzt wird. Präfix-Kompression wird bei Schlüsseln benutzt, die mit einer Zeichenkette beginnen. Präfix-Kompression hilft, wenn es viele Zeichenketten mit identischem Präfix gibt.

Bei MyISAM-Tabellen können Sie auch Zahlen Präfix-komprimieren, indem Sie beim Erzeugen der Tabelle PACK_KEYS=1 angeben. Das hilft, wenn Sie viele Ganzzahl-Schlüssel mit identischem Präfix haben, wenn die Zahlen mit dem hohen Byte zuerst gespeichert werden.

8.1.2. MyISAM-Tabellenformate

MyISAM unterstützt 3 verschiedene Tabellentypen. Zwei von ihnen werden automatisch gewählt, abhängig vom Spaltentyp, den Sie benutzen. Der dritte, komprimierte Tabellen, kann nur mit dem myisampack-Dienstprogramm erzeugt werden.

Wenn Sie eine Tabelle erzeugen (CREATE) oder ändern (ALTER), können Sie bei Tabellen, die kein BLOB enthalten, ein dynamisches (DYNAMIC) oder festes (FIXED) Tabellenformat mit der ROW_FORMAT=#-Tabellenoption erzwingen. Zukünftig werden Sie in der Lage sein, Tabellen zu komprimieren / dekomprimieren, indem Sie ROW_FORMAT=compressed | default für ALTER TABLE angeben. See Abschnitt 7.5.3, „CREATE TABLE-Syntax“.

8.1.2.1. Kennzeichen statischer (Festlängen-) Tabellen

Das ist das vorgabemäßige Format. Es wird benutzt, wenn die Tabelle keine VARCHAR-, BLOB- oder TEXT-Spalten enthält.

Dieses Format ist das einfachste und sicherste Format. Es ist auch das schnellste der Formate auf Platte. Die Geschwindigkeit ergibt sich aus der einfachen Weise, wie Daten auf der Platte gefunden werden können. Wenn man etwas mit einem Index und statischem Format nachschlägt, ist es sehr einfach. Man multipliziert einfach die Zeilennummer mit der Zeilenlänge.

Wenn eine Tabelle gescannt wird, ist es ausserdem sehr einfach, mit jedem Plattenzugriff eine konstante Anzahl von Datensätzen zu lesen.

Die Sicherheit zeigt sich, wenn Ihr Computer beim Schreiben in eine MyISAM-Datei fester Länge abstürzt. In diesem Fall kann myisamchk leicht herausfinden, wo jede Zeile anfängt und aufhört. Daher kann es üblicherweise alle Datensätze mit Ausnahme desjenigen, in den nur teilweise geschrieben wurde, wieder herstellen. Beachten Sie, dass in MySQL alle Indexe in jedem Fall wiederhergestellt werden können:

  • Alle CHAR-, NUMERIC- und DECIMAL-Spalten werden mit Leerzeichen auf die Spaltenbreite aufgefüllt.

  • Sehr schnell.

  • Leicht zu cachen.

  • Nach einem Absturz leicht zu rekonstruieren, weil sich Datensätze an festen Positionen befinden.

  • müssen nicht (mit myisamchk) reorganisiert werden, es sei denn, eine riesige Anzahl von Datensätzen wurde gelöscht und Sie wollen dem Betriebssystem freien Speicherplatz zurückgeben.

  • Benötigen normalerweise mehr Speicherplatz als dynamische Tabellen.

8.1.2.2. Kennzeichen dynamischer Tabellen

Dieses Format wird benutzt, wenn die Tabelle irgend welche VARCHAR-, BLOB- oder TEXT-Spalten enthält, oder wenn die Tabelle mit ROW_FORMAT=dynamic erzeugt wurde.

Dieses Format ist etwas komplexer, weil jede Zeile einen Header haben muss, der aussagt, wie lang sie ist. Ein Datensatz kann ausserdem an mehr als einem Speicherplatz enden, wenn er bei einer Aktualisierung verlängert wird.

Sie können OPTIMIZE table oder myisamchk benutzen, um eine Tabelle zu defragmentieren. Wenn Sie statische Daten haben, auf die Sie oft zugreifen oder die Sie in derselben Tabelle oft ändern, als VARCHAR- oder BLOB-Spalten haben, ist es eine gute Idee, die dynamischen Spalten in andere Tabellen zu verschieben, einfach um Fragmentierung zu vermeiden:

  • Alle Zeichenketten-Spalten sind dynamisch (ausser denen mit einer Länge kleiner 4).

  • Jedem Datensatz ist eine Bitmap vorangestellt, die angibt, welche Spalten bei Zeichenketten-Spalten leer ('') sind oder 0 bei numerischen Spalten. (Das ist nicht dasselbe wie Spalten, die NULL-Werte enthalten.) Wenn eine Zeichenketten-Spalte nach der Entfernung von Leerzeichen am Ende eine Länge von 0 hat oder eine numerische Spalte einen Wert von 0 hat, wird sie in der Bitmap markiert und nicht auf Platte gespeichert. Nicht leere Zeichenketten werden als ein Längen-Byte plus dem Zeichenketten-Inhalt gespeichert.

  • Benötigen üblicherweise weniger Plattenplatz als Festlängen-Tabellen.

  • Jeder Datensatz benutzt nur so viel Speicherplatz wie erforderlich. Wenn ein Datensatz größer wird, wird er in so viele Teile wie erforderlich aufgeteilt. Hierdurch wird Datensatzfragmentierung hervorgerufen.

  • Wenn Sie eine Zeile mit Informationen aktualisieren, die die Zeilenlänge überschreiten, wird die Zeile fragmentiert. In diesem Fall sollten Sie von Zeit zu Zeit myisamchk -r laufen lassen, um bessere Performance zu erzielen. Benutzen Sie myisamchk -ei tabellen_name, um einige statistische Informationen zu erhalten.

  • Sind nach einem Absturz nicht so einfach zu rekonstruieren, weil ein Datensatz in viele Teile fragmentiert sein und ein Link (Fragment) fehlen kann.

  • Die erwartete Zeilenlänge bei Datensätzen dynamischer Länge ist:

    3
    + (anzahl_der_spalten + 7) / 8
    + (anzahl_der_zeichenketten_spalten)
    + komprimierte_groesse_numerischer_spalten
    + laenge_von_zeichenketten
    + (anzahl_von_NULL_spalten + 7) / 8
    

    Für jeden Link kommen 6 Bytes hinzu. Ein dynamischer Datensatz wird immer dann verknüpft (linked), wenn eine Aktualisierung eine Vergrößerung des Datensatzes bewirkt. Jede neue Verknüpfung hat mindestens 20 Bytes, so dass die nächste Vergrößerung wahrscheinlich in dieselbe Verknüpfung passt. Wenn nicht, entsteht eine weitere Verknüpfung. Sie können mit myisamchk -ed prüfen, wie viele Verknüpfungen es gibt. Alle Verknüpfungen können mit myisamchk -r entfernt werden.

8.1.2.3. Kennzeichen komprimierter Tabellen

Das ist ein Nur-Lese-Typ, der mit dem optionalen myisampack-Dienstprogramm (pack_isam für ISAM-Tabellen) erzeugt wird:

  • All MySQL-Distributionen, selbst diejenigen, die es vor der GPL-Version von MySQL gab, können Tabellen lesen, die mit myisampack komprimiert wurden.

  • Komprimierte Tabellen benötigen viel weniger Speicherplatz. Das minimiert Plattenzugriffe, was sehr nett ist, wenn Sie langsame Platten benutzen (wie CD-ROMs).

  • Jeder Datensatz wird separat komprimiert (sehr geringer Zugriffs-Overhead). Der Header für einen Datensatz hat eine feste Länge (1 bis 3 Bytes), abhängig vom größten Datensatz in der Tabelle. Jede Spalte wird unterschiedlich komprimiert. Einige Kompressionstypen sind:

    • Für jede Spalte gibt es üblicherweise eine unterschiedliche Huffman-Tabelle.

    • Komprimierung von Leerzeichen am Ende.

    • Komprimierung von Leerzeichen am Anfang.

    • Zahlen mit dem Wert 0 werden mit 1 Bit gespeichert.

    • Wenn Werte in einer Ganzzahl-Spalte einen kleinen Wertebereich haben, wird die Spalte mit dem kleinsten möglichen Typ gespeichert. Eine BIGINT-Spalte (8 Bytes) kann beispielsweise als TINYINT-Spalte (1 Byte) gespeichert werden, wenn sich alle Werte im Bereich von 0 bis 255 befinden.

    • Wenn eine Spalte nur einen kleinen Satz möglicher Werte besitzt, wird der Spaltentyp zu ENUM umgewandelt.

    • Eine Spalte kann auch eine Kombination der obigen Komprimierungen benutzen.

  • Kann Datensätze fester oder dynamischer Länge handhaben, aber nicht BLOB- oder TEXT-Spalten.

  • Kann mit myisamchk dekomprimiert werden.

8.1.3. MyISAM-Tabellenprobleme

Das Dateiformat, das MySQL benutzt, um Daten zu speichern, wurde ausgiebig getestet, aber es gibt immer Umstände, die dazu führen können, dass Datenbanktabellen beschädigt werden.

8.1.3.1. Beschädigte MyISAM-Tabellen

Obwohl das MyISAM-Tabellenformat sehr zuverlässig ist (alle Änderungen an einer Tabelle werden geschrieben, bevor das SQL-Statement zurückkehrt), können Sie dennoch beschädigte Tabellen bekommen, wenn eines der folgenden Dinge passiert:

  • Der mysqld-Prozess wird mitten in einem Schreibvorgang gekillt.

  • Unerwartetes Herunterfahren des Computers (wenn der Computer beispielsweise abgeschaltet wird).

  • Ein Hardware-Fehler.

  • Sie benutzen ein externes Programm (wie myisamchk) auf einer benutzten Tabelle.

  • Ein Software-Bug im MySQL- oder MyISAM-Code.

Typische Symptome einer beschädigten Tabelle sind:

  • Sie erhalten den Fehler Incorrect key file for table: '...'. Try to repair it, wenn Sie Daten aus der Tabelle auswählen.

  • Anfragen finden keine Zeilen in der Tabelle oder geben unvollständige Daten zurück.

Sie können mit dem Befehl CHECK TABLE prüfen, ob eine Tabelle in Ordnung ist. See Abschnitt 5.4.4, „CHECK TABLE-Syntax“.

Sie können eine beschädigte Tabelle mit REPAIR TABLE reparieren. See Abschnitt 5.4.5, „REPAIR TABLE-Syntax“. Wenn mysqld nicht läuft, können Sie eine Tabelle auch mit dem myisamchk-Befehl reparieren. myisamchk-Syntax.

Wenn Ihre Tabellen oft beschädigt werden, sollten Sie versuchen, den Grund dafür herauszufinden! See Abschnitt A.4.1, „Was zu tun ist, wenn MySQL andauernd abstürzt“.

In diesem Fall ist es am wichtigsten zu wissen, ob die Tabelle durch einen Absturz von mysqld beschädigt wurde (das können Sie leicht feststellen, wenn es eine aktuelle Zeile restarted mysqld in der mysqld-Fehlerdatei gibt). Wenn das nicht der Fall ist, sollten Sie versuchen, daraus einen Testfall zu machen. See Abschnitt D.1.6, „Einen Testfall herstellen, wenn Sie Tabellenbeschädigung feststellen“.

8.1.3.2. Client benutzt Tabelle oder hat sie nicht korrekt geschlossen

Jede MyISAM-.MYI-Datei hat im Header einen Zähler, der benutzt werden kann, um zu prüfen, ob die Tabelle korrekt geschlossen wurde.

Wenn Sie folgende Warnmeldung von CHECK TABLE oder myisamchk erhalten:

# client is using or hasn't closed the table properly

heißt das, dass der Zähler nicht mehr synchron ist. Das bedeutet nicht, dass die Tabelle beschädigt ist, aber Sie sollten zumindest eine Überprüfung vornehmen, um sicherzustellen, dass die Tabelle in Ordnung ist.

Der Zähler funktioniert wie folgt:

  • Wenn die Tabelle das erste Mal in MySQL aktualisiert wird, wird der Zähler im Header der Index-Dateien heraufgezählt.

  • Der Zähler wird während weiterer Aktualisierungen nicht verändert.

  • Wenn die letzte Instanz einer Tabelle geschlossen wird (wegen eines FLUSH oder weil es nicht mehr genug Platz im Tabellen-Cache gibt), wird der Zähler heruntergezählt, wenn die Tabelle zu irgend einem Zeitpunkt aktualisiert wurde.

  • Wenn Sie eine Tabelle reparieren oder prüfen und sie in Ordnung ist, wird der Zähler auf 0 zurückgesetzt.

  • Um Probleme zu vermeiden, die durch Interaktion mit anderen Prozessen entstehen, die vielleicht eine Prüfung der Tabelle durchführen, wird der Zähler beim Schließen nicht heruntergezählt, wenn er 0 war.

Mit anderen Worten kann der Zähler nur in folgenden Fällen nicht mehr synchron sein:

  • Die MyISAM-Tabellen werden ohne LOCK und FLUSH TABLES kopiert.

  • MySQL ist zwischen einer Aktualisierung und dem endgültigen Schließen abgestürzt. (Beachten Sie, dass die Tabelle trotzdem in Ordnung sein kann, weil MySQL stets für alles zwischen jedem Statement Schreibvorgänge durchführt.

  • Jemand hat myisamchk --repair oder myisamchk --update-state auf eine Tabelle ausgeführt, die durch mysqld in Benutzung war.

  • Viele mysqld-Server benutzen die Tabelle und einer davon hat REPAIR oder CHECK der Tabelle ausgeführt, während sie durch einen anderen Server in Benutzung war. Hierbei kann CHECK sicher ausgeführt werden (selbst wenn Sie Warnungen von anderen Servern erhalten werden), aber REPAIR sollte vermieden werden, weil es momentan die Daten-Datei durch eine neue ersetzt, was anderen Servern nicht signalisiert wird.

8.2. MERGE-Tabellen

MERGE-Tabellen sind neu seit MySQL-Version 3.23.25. Der Code ist noch Gamma, sollte aber ausreichend stabil sein.

Eine MERGE-Tabelle (auch bekannt als MRG_MyISAM-Tabelle) ist eine Sammlung identischer MyISAM-Tabellen, die wie eine benutzt werden können. Sie können auf dieser Sammlung von Tabellen nur SELECT, DELETE und UPDATE ausführen. Wenn Sie eine MERGE-Tabelle löschen (DROP), löschen Sie nur die MERGE-Spezifikation.

Beachten Sie, dass DELETE FROM merge_tabelle ohne WHERE nur das Mapping für die Tabelle löscht, nicht alles in den gemappten Tabellen. (Geplant ist, das in Version 4.1 zu beheben.)

Mit identischen Tabellen ist gemeint, dass alle Tabellen mit identischen Spalten- und Schlüsselinformationen erzeugt wurden. Sie können kein MERGE auf Tabellen ausführen, deren Spalten unterschiedlich komprimiert sind, nicht genau dieselben Spalten oder die Schlüssel in unterschiedlicher Reihenfolge haben. Einige der Tabellen können jedoch mit myisampack komprimiert sein. See Abschnitt 5.7.4, „myisampack, MySQL-Programm zum Erzeugen komprimierter Nur-Lese-Tabellen“.

Wenn Sie eine MERGE-Tabelle erzeugen, erhalten Sie eine .frm-Tabellendefinitionsdatei und eine .MRG-Tabellenlistendatei. Die .MRG enthält lediglich eine Liste der Index-Dateien (.MYI-Dateien), die wie eine benutzt werden sollen. Alle benutzten Tabellen müssen in derselben Datenbank wie die MERGE-Tabelle selbst sein.

Momentan benötigen Sie SELECT-, UPDATE- und DELETE-Berechtigungen für die Tabellen, die Sie auf eine MERGE-Tabelle mappen.

MERGE-Tabellen können bei der Lösung folgender Probleme helfen:

  • Auf einfache Weise einen Satz von Log-Tabellen verwalten. Beispielsweise können Sie Daten aus unterschiedlichen Monaten in separaten Dateien speichern, einige davon mit myisampack komprimieren und dann eine MERGE-Tabelle erzeugen, um sie wie eine zu benutzen.

  • Mehr Geschwindigkeit. Sie können eine große Nur-Lese-Tabelle nach bestimmten Kriterien aufspalten und die verschiedenen Tabellenteile auf unterschiedlichen Festplatten speichern. Eine MERGE-Tabelle darauf könnte viel schneller sein als die große Tabelle zu benutzen. (Natürlich können Sie auch ein RAID benutzen, um dieselben Vorteile zu erzielen.)

  • Effizientere Suchen durchführen. Wenn Sie genau wissen, wonach Sie suchen, können Sie mit einigen Anfragen in lediglich einer der aufgespaltenen Tabellen suchen und die MERGE-Tabelle für andere benutzen. Es können sogar viele unterschiedliche MERGE-Tabellen aktiv sein, möglicherweise mit Dateien, die sich überlappen.

  • Effizientere Reparaturen durchführen. Es ist leichter, die individuellen Dateien zu reparieren, die auf eine MERGE-Datei gemappt sind, als eine wirklich große Datei zu reparieren.

  • Sofortiges Mappen vieler Dateien als einer. Eine MERGE-Tabelle benutzt den Index der individuellen Tabellen. Sie muss selbst keinen eigenen Index warten. Dadurch können Sie MERGE-Tabellensammlungen SEHR schnell erzeugen oder neu mappen. Beachten Sie, dass Sie die Schlüsseldefinitionen angeben, wenn Sie eine MERGE-Tabelle erzeugen!

  • Wenn Sie einen Satz von Tabellen bei Bedarf oder im Stapel zu einer großen Tabelle vereinigen, sollten Sie statt dessen bei Bedarf eine MERGE-Tabelle darauf erzeugen. Das ist viel schneller und spart eine Menge Speicherplatz.

  • Umgehen der Dateigrößengrenze des Betriebssystems.

  • Sie können ein Alias / Synonym für eine Tabelle erzeugen, indem Sie sie einfach ein MERGE über eine Tabelle benutzen. Das sollte keine spürbaren Performance-Auswirkungen haben (nur eine Reihe indirekter Aufrufen und memcpy's bei jedem Lesen).

Die Nachteile von MERGE-Tabellen sind:

  • Sie können nur identische MyISAM-Tabellen für eine MERGE-Tabelle benutzen.

  • AUTO_INCREMENT-Spalten werden bei INSERT nicht automatisch aktualisiert.

  • REPLACE funktioniert nicht.

  • MERGE-Tabellen benutzen mehr Datei-Deskriptoren. Wenn Sie eine MERGE benutzen, die über 10 Tabellen mappt, und 10 Benutzer diese benutzen, benötigen Sie 10 * 10 + 10 Datei-Deskriptoren (10 Daten-Dateien für 10 Benutzer und 10 gemeinsam genutzte Index-Dateien).

  • Lesevorgänge von Schlüsseln sind langsamer. Wenn Sie eine Leseoperation auf einen Schlüssel durchführen, muss der MERGE-Handler ein Lesen auf alle zugrunde liegenden Tabellen ausführen, um zu prüfen, welche am nächsten zum angegebenen Schlüssel passt. Wenn Sie ein 'Lese nächsten' ausführen, muss der MERGE-Handler die Lese-Puffer durchsuchen, um den nächsten Schlüssel zu finden. Erst wenn ein Schlüsselpuffer aufgebraucht ist, muss der Handler den nächsten Schlüsselblock lesen. Das macht MERGE-Schlüssel bei eq_ref-Suchen viel langsamer, aber nicht viel langsamer bei ref-Suchen. See Abschnitt 6.2.1, „EXPLAIN-Syntax (Informationen über ein SELECT erhalten)“.

  • Sie können kein DROP TABLE, ALTER TABLE oder DELETE FROM tabelle ohne eine WHERE-Klausel auf jeder Tabelle, die von einer MERGE-Tabelle gemappt ist, ausführen, wenn diese 'offen' ist. Wenn Sie das tun, könnte die MERGE-Tabelle immer noch auf die Originaltabelle verweisen, und Sie würden unerwartete Ergebnisse erhalten.

Wenn Sie eine MERGE-Tabelle erzeugen, müssen Sie mit UNION(liste-von-tabellen) angeben, welche Tabellen Sie wie eine benutzen wollen. Optional können Sie mit INSERT_METHOD angeben, ob Sie wollen, dass Einfügungen in die MERGE-Tabelle in der ersten oder der letzten Tabelle in der UNION-Liste geschehen sollen. Wenn Sie keine INSERT_METHOD oder NO angeben, geben alle INSERT-Befehle auf die MERGE-Tabelle einen Fehler zurück.

Folgendes Beispiel zeigt, wie Sie MERGE-Tabellen benutzen:

CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY, nachricht CHAR(20));
CREATE TABLE t2 (a INT AUTO_INCREMENT PRIMARY KEY, nachricht CHAR(20));
INSERT INTO t1 (nachricht) VALUES ("test"),("tabelle"),("t1");
INSERT INTO t2 (nachricht) VALUES ("test"),("tabelle"),("t2");
CREATE TABLE gesamt (a INT NOT NULL, nachricht CHAR(20), KEY(a)) TYPE=MERGE UNION=(t1,t2) INSERT_METHOD=LAST;

Beachten Sie, dass wir keinen UNIQUE- oder PRIMARY KEY-Schlüssel in der gesamt-Tabelle angegeben haben, weil der Schlüssel in der gesamt-Tabelle nicht eindeutig sein wird.

Beachten Sie auch, dass Sie die .MRG-Datei direkt von ausserhalb des MySQL-Servers manipulieren können:

shell> cd /mysql-data-verzeichnis/aktuelle-datenbank
shell> ls -1 t1.MYI t2.MYI > gesamt.MRG
shell> mysqladmin flush-tables

Jetzt können Sie Dinge wie folgendes tun:

mysql> select * from gesamt;
+---+-----------+
| a | nachricht |
+---+-----------+
| 1 | test      |
| 2 | table     |
| 3 | t1        |
| 1 | test      |
| 2 | table     |
| 3 | t2        |
+---+-----------+

Um eine MERGE-Tabelle neu zu mappen, können Sie folgendes tun:

  • Die Tabelle löschen (DROP) und neu erzeugen.

  • ALTER TABLE tabelle UNION(...) benutzen.

  • Die .MRG-Datei ändern und ein FLUSH TABLE auf die MERGE-Tabelle und alle zugrunde liegenden Tabellen ausführen, um den Handler zu zwingen, die neue Definitionsdatei einzulesen.

8.2.1. MERGE-Tabellenprobleme.

Folgende Probleme sind bei MERGE-Tabellen bekannt:

  • DELETE FROM merge_tabelle ohne WHERE löscht nur das Mapping für die Tabelle, nicht alles in den gemappten Tabellen.

  • RENAME TABLE auf eine Tabelle, die in einer aktiven MERGE-Tabelle benutzt wird, kann die Tabelle beschädigen. Das wird in MySQL 4.0.x behoben.

  • Beim Erzeugen einer Tabelle des Typs MERGE wird nicht geprüft, ob die zugrunde liegenden Tabellen kompatible Typen sind. Wenn Sie MERGE-Tabellen in dieser Weise benutzen, ist es sehr wahrscheinlich, dass merkwürdige Probleme auftauchen.

  • Wenn Sie ALTER TABLE benutzen, um als erstes eine UNIQUE-Index zu einer Tabelle hinzuzufügen, die in einer MERGE-Tabelle benutzt wird, und dann ALTER TABLE benutzen, um einen normalen Index auf die MERGE-Tabelle hinzuzufügen, wird die Schlüssel-Reihenfolge für die Tabellen anders sein, wenn es einen alten, nicht eindeutigen Schlüssel in der Tabelle gab. Das liegt daran, dass ALTER TABLE UNIQUE-Schlüssel vor normale Schlüssel einfügt, um in der Lage zu sein, doppelte Schlüsseleinträge so früh wie möglich zu erkennen.

  • Der Bereichsoptimierer kann MERGE-Tabellen noch nicht effizient benutzen und kann manchmal nicht optimale Joins produzieren. Das wird in MySQL 4.0.x behoben.

  • DROP TABLE auf eine Tabelle, die in einer MERGE-Tabelle benutzt wird, funktioniert unter Windows nicht, weil der MERGE-Handler das Tabellen-Mapping versteckt vor der oberen Ebene von MySQL durchführt. Weil Windows es nicht zuläßt, dass Dateien gelöscht werden, die offen sind, müssen Sie zuerst alle MERGE-Tabellen auf Platte zurückschreiben (mit FLUSH TABLES) oder die MERGE-Tabelle löschen, bevor Sie die Tabelle löschen. Das wird zu dem Zeitpunkt behoben, wenn Sichten (VIEWs) eingeführt werden.

8.3. ISAM-Tabellen

Sie können auch den veralteten ISAM-Tabellentyp benutzen. Dieser wird recht bald verschwinden (wahrscheinlich in MySQL 4.1), weil MyISAM eine bessere Implementation derselbe Sache ist. ISAM benutzt einen B-tree-Index. Der Index wird in einer Datei mit der Endung .ISM gespeichert, und die Daten in einer Datei mit der Endung .ISD. Sie können ISAM-Tabellen mit dem isamchk-Dienstprogramm prüfen / reparieren. See Abschnitt 5.4, „Katastrophenschutz und Wiederherstellung“.

ISAM hat folgende Features / Eigenschaften:

  • Komprimierte und Festlängen-Schlüssel

  • Feste und dynamische Datensatzlängen

  • 16 Schlüssel mit 16 Schlüsselteilen pro Schlüssel

  • Maximale Schlüssellänge 256 (Vorgabe)

  • Daten werden im Maschinenformat gespeichert. Das ist schnell, aber Maschinen- / Betriebssystem-abhängig.

Die meisten Dinge, die für MyISAM-Tabellen gelten, gelten auch für ISAM-Tabellen. See Abschnitt 8.1, „MyISAM-Tabellen“. Die größten Unterschiede im Vergleich zu MyISAM sind:

  • ISAM-Tabellen sind nicht binärportabel zwischen verschiedenen Betriebssystemen / Plattformen.

  • Handhabt keine Tabellen > 4 GB.

  • Unterstützt nur Präfix-Komprimierung von Zeichenketten.

  • Kleinere Schlüssel-Beschränkungen.

  • Dynamische Tabelle werden schneller fragmentiert.

  • Tabellen werden mit pack_isam statt mit myisampack komprimiert.

Wenn Sie eine ISAM-Tabelle in eine MyISAM-Tabelle umwandeln wollen, können Sie Dienstprogramme wie mysqlcheck oder ein ALTER TABLE-Statement benutzen:

mysql> ALTER TABLE tabelle TYPE = MYISAM;

Die eingebetteten (embedded) MySQL-Versionen unterstützen keine ISAM-Tabellen.

8.4. HEAP-Tabellen

HEAP-Tabellen benutzen eine gehashten Index und werden im Arbeitsspeicher gespeichert. Das macht sie sehr schnell, aber wenn MySQL abstürzt, verlieren Sie alle darin gespeicherten Daten. HEAP ist sehr nützlich für temporäre Tabellen.

Die MySQL-internen HEAP-Tabellen benutzen 100% dynamisches Hashen ohne Overflow-Bereiche. Es wird kein zusätzlicher Platz für freie Listen benötigt. HEAP-Tabellen haben auch keine Probleme mit Löschen plus Einfügen, was normalerweise bei gehashten Tabellen häufig vorkommt:

mysql> CREATE TABLE test TYPE=HEAP SELECT ip,SUM(downloads) as down
        FROM log_tabelle GROUP BY ip;
mysql> SELECT COUNT(ip),AVG(down) FROM test;
mysql> DROP TABLE test;

Einige Dinge sollten Sie bei der Benutzung von HEAP-Tabellen in Betracht ziehen:

  • Sie sollten immer MAX_ROWS im CREATE-Statement angeben, um sicherzustellen, dass Sie nicht versehentlich den gesamten Arbeitsspeicher benutzen.

  • Indexe werden nur bei = und <=> benutzt (sind aber SEHR schnell).

  • HEAP-Tabellen können nur ganze Schlüssel benutzen, um nach einer Zeile zu suchen. Vergleichen Sie das mit MyISAM-Tabellen, bei denen jedes Präfix des Schlüssels für das Suchen von Zeilen benutzt werden kann.

  • HEAP-Tabellen benutzen ein festes Datensatzlängenformat.

  • HEAP unterstützt keine BLOB/TEXT-Spalten.

  • HEAP unterstützt keine AUTO_INCREMENT-Spalten.

  • HEAP unterstützt keinen Index auf eine NULL-Spalte.

  • Es darf keine nicht eindeutigen Schlüssel auf eine HEAP-Tabelle geben (das ist ungebräuchlich für gehashte Tabellen).

  • HEAP-Tabellen werden von allen Clients gemeinsam benutzt (so wie jede andere Tabelle).

  • Sie können nicht nach dem nächsten Eintrag in der Reihenfolge suchen (also den Index benutzen, um ein ORDER BY zu machen).

  • Die Daten für HEAP-Tabellen werden in kleinen Blöcken zugewiesen. Die Tabellen sind 100% dynamisch (beim Einfügen). Es werden keine Overflow-Bereiche und kein zusätzlicher Platz für Schlüssel benötigt. Gelöschte Zeilen werden in eine verknüpfte Liste geschrieben und wieder benutzt, wenn Sie neue Daten in die Tabelle einfügen.

  • Sie brauchen genug zusätzlichen Arbeitsspeicher für alle HEAP-Tabellen, die Sie zugleich benutzen wollen.

  • Um Speicher freizugeben, führen Sie DELETE FROM heap_tabelle, TRUNCATE heap_tabelle oder DROP TABLE heap_tabelle aus.

  • MySQL kann nicht herausfinden, wie viele Zeilen es zwischen zwei Werten ungefähr gibt (das wird vom Bereichsoptimierer benötigt, um zu entscheiden, welcher Index benutzt wird). Das kann einige Anfragen betreffen, wenn Sie eine MyISAM-Tabelle in eine HEAP-Tabelle umwandeln.

  • Um sicherzustellen, dass Sie nicht versehentlich etwas Unkluges tun, können Sie keine HEAP-Tabellen größer als max_heap_table_size erzeugen.

Der für eine Zeile in einer HEAP-Tabelle benötigte Speicher ist:

SUM_OVER_ALL_KEYS(max_length_of_key + sizeof(char*) * 2)
+ ALIGN(length_of_row+1, sizeof(char*))

sizeof(char*) ist 4 auf 32-Bit-Maschinen und 8 auf 64-Bit-Maschinen.

8.5. InnoDB-Tabellen

8.5.1. Überblick über InnoDB-Tabellen

InnoDB stellt MySQL einen transaktionssicheren (ACID-kompatiblen) Tabellen-Handler mit Fähigkeiten für Commit, Rollback und Reparatur nach Absturz zur Verfügung. InnoDB beherrscht Sperren auf Zeilenebene sowie ein konsistentes, nicht sperrendes Lesen in der Art von Oracle bei SELECTs. Diese Features steigern die Handhabung gleichzeitiger Verbindungen und die Performance. Es gibt bei InnoDB keine Notwendigkeit für Sperr-Eskalation, weil die Sperren auf Zeilenebene bei InnoDB in sehr wenig Speicherplatz passen. InnoDB-Tabellen unterstützen als erster Tabellentyp in MySQL FOREIGN KEY-Beschränkungen.

InnoDB wurde für maximale Performance bei der Bearbeitung großer Datenmengen entworfen. Seine Prozessor-Effizienz wird wahrscheinlich von keiner anderen Festplatten-basierenden relationalen Datenbank-Engine erreicht.

Technisch gesehen ist InnoDB ein komplettes Datenbank-Backend, das unter MySQL platziert ist. InnoDB hat seinen eigenen Puffer-Pool, um Daten und Indexe im Hauptspeicher zu cachen. InnoDB speichert seine Tabellen und Indexe in einem Tabellenplatz (Tablespace), der aus mehreren Dateien bestehen kann. Das unterscheidet sich beispielsweise von MyISAM-Tabellen, bei denen jede Tabelle als separate Datei gespeichert ist. InnoDB-Tabellen können jede beliebige Größe annehmen, sogar auf Betriebssystemen, deren Dateigröße auf 2 GB beschränkt ist.

Die neuesten Informationen über InnoDB finden Sie unter http://www.innodb.com/. Die aktuellste Version des InnoDB-Handbuchs ist immer dort zu finden, und Sie können auch kommerzielle Lizenzen und kommerziellen Support für InnoDB bestellen.

InnoDB wird momentan (Oktober 2001) für die Produktion auf mehreren großen Datenbank-Sites benutzt, die hohe Performance benötigen. Die bekannte Internet-Newssite Slashdot.org läuft auf InnoDB. Mytrix Inc. speichert über 1 TB an Daten in InnoDB, und eine andere Site handhabt eine durchschnittliche Last von 800 Einfüge- und Update-Operationen pro Sekunde mit InnoDB.

InnoDB-Tabellen sind in der MySQL-Quelldistribution ab Version 3.23.34a enthalten und in der MySQL-Max-Binärversion aktiviert. Für Windows sind die Max-Binärdateien in der Standarddistribution enthalten.

Wenn Sie eine Binärversion von MySQL herunter geladen haben, die Unterstützung für InnoDB enthält, folgen Sie einfach den Anweisungen im Handbuch für die Installation einer Binärversion von MySQL. Wenn Sie bereits MySQL-3.23 installiert haben, können Sie MySQL-Max am einfachsten installieren, indem Sie die ausführbare Datei für den Server (mysqld) durch die entsprechende ausführbare Datei in der Max-Distribution ersetzen. MySQL and MySQL-Max unterscheiden sich nur in Bezug auf die ausführbare Datei für den Server. See Abschnitt 3.2.6, „MySQL-Binärdistributionen, die von MySQL AB kompiliert wurden“. See Abschnitt 5.7.5, „mysqld-max, ein erweiterter mysqld-Server“.

Um MySQL mit InnoDB-Unterstützung zu kompilieren, laden Sie MySQL-3.23.34a oder neuer von http://www.mysql.com/ herunter und konfigurieren Sie MySQL mit der --with-innodb-Option. Sehen Sie im Handbuch unter Abschnitt 3.3, „Installation der Quelldistribution“ nach.

cd /pfad/zur/quelldistribution/von/mysql-3.23.37
./configure --with-innodb

Um InnoDB zu benutzen, müssen Sie InnoDB init in Ihrer my.cnf- oder my.ini-Datei angeben. In dieser Datei müssen Sie mindestens folgenden Zeile im [mysqld]-Abschnitt hinzufügen:

innodb_data_file_path=ibdata:30M

Für eine gute Performance ist es jedoch am besten, Optionen wie die unten im Abschnitt Abschnitt 8.5.2, „Mit InnoDB anfangen - Optionen“ empfohlenen anzugeben.

InnoDB wird unter der GNU-GPL-Lizenz Version 2 (vom Juni 1991) vertrieben. In den Quelldistributionen von MySQL erscheint InnoDB als Unterverzeichnis.

8.5.2. Mit InnoDB anfangen - Optionen

Um InnoDB-Tabellen in MySQL-Max-3.23 zu benutzen, MÜSSEN Sie Konfigurationsparameter im [mysqld]-Abschnitt der MySQL-Konfigurationsdatei my.cnf angeben. See Abschnitt 5.1.2, „my.cnf-Optionsdateien“.

Der einzige erforderliche Parameter, um InnoDB in MySQL-Max-3.23 benutzen zu können, ist innodb_data_file_path. In MySQL-4.0 müssen Sie nicht einmal innodb_data_file_path angeben. Vorgabemäßig wird eine 64 MB große Daten-Datei ibdata1 im datadir von MySQL erzeugt.

Um jedoch eine gute Performance zu erzielen, MÜSSEN Sie explizit die unten in Beispielen aufgeführten InnoDB-Parameter setzen.

Der Vorgabewert für innodb_data_home_dir ist das datadir von MySQL. Wenn Sie innodb_data_home_dir nicht angeben, können Sie in innodb_data_file_path keine absoluten Pfade benutzen.

Nehmen wir an, Sie haben eine Windows-NT-Maschine mit 128 MB RAM und einer einzelnen 10 GB großen Festplatte. Unten steht ein Beispiel von möglichen Konfigurationsparametern in my.cnf für InnoDB:

[mysqld]
# Hier können Ihre sonstigen MySQL-Serveroptionen stehen
# ...
#
innodb_data_home_dir = c:\ibdata
# Die Daten-Dateien müssen in der Lage sein,
# Ihre Daten und Indexe aufzunehmen
innodb_data_file_path = ibdata1:2000M;ibdata2:2000M
# Puffer-Poolgröße auf 50% bis 80%
# des Arbeitsspeichers Ihres Computers setzen
set-variable = innodb_buffer_pool_size=70M
set-variable = innodb_additional_mem_pool_size=10M
innodb_log_group_home_dir = c:\iblogs
# .._log_arch_dir muss dasselbe sein wie
# .._log_group_home_dir
innodb_log_arch_dir = c:\iblogs
innodb_log_archive=0
set-variable = innodb_log_files_in_group=3
# Die Log-Dateigröße auf ungefähr 15%
# der Puffer-Poolgröße setzen
set-variable = innodb_log_file_size=10M
set-variable = innodb_log_buffer_size=8M
# ..flush_log_at_trx_commit auf 0 setzen,
# wenn Sie es sich leisten können,
# ein paar der letzten Transaktionen zu verlieren
innodb_flush_log_at_trx_commit=1
set-variable = innodb_file_io_threads=4
set-variable = innodb_lock_wait_timeout=50

Beachten Sie, dass die Daten-Dateien bei einigen Betriebssystemen kleiner als 2 GB sein müssen! Die Gesamtgröße von Daten-Dateien muss größer oder gleich 10 MB sein. Die Gesamtgröße der Log-Dateien MUSS auf 32-Bit-Computern kleiner als 4 GB sein.

InnoDB legt keine Verzeichnisse an. Diese müssen Sie selbst erzeugen! Stellen Sie auch sicher, dass der MySQL-Server Rechte hat, Dateien in den Verzeichnissen anzulegen, die Sie angeben.

Wenn Sie zum ersten Mal eine InnoDB-Datenbank erzeugen, sollten Sie den MySQL-Server am besten von der Kommandozeilen-Eingabeaufforderung starten. InnoDB gibt dann Informationen über die Datenbank-Erzeugung auf dem Bildschirm aus und Sie sehen, was passiert. Unten in Abschnitt 3 sehen Sie, wie die Ausgaben aussehen sollten. Unter Windows können Sie mysqld-max.exe so starten:

ihr-pfad-zu-mysqld>mysqld-max --standalone --console

Nehmen wir an, Sie haben einen Linux-Computer mit 512 MB RAM und drei Festplatten mit jeweils 20 GB (in Verzeichnispfaden /, /dr2 and /dr3). Unten ist ein Beispiel möglicher Konfigurationsparameter in my.cnf für InnoDB:

[mysqld]
# Hier können Ihre sonstigen MySQL-Serveroptionen stehen
# ...
#
innodb_data_home_dir = /
# Die Daten-Dateien müssen in der Lage sein,
# Ihre Daten und Indexe aufzunehmen
innodb_data_file_path = ibdata/ibdata1:2000M;dr2/ibdata/ibdata2:2000M
# Puffer-Poolgröße auf 50% bis 80%
# des Arbeitsspeichers Ihres Computers setzen
set-variable = innodb_buffer_pool_size=350M
set-variable = innodb_additional_mem_pool_size=20M
innodb_log_group_home_dir = /dr3/iblogs
# .._log_arch_dir muss dasselbe sein wie
# .._log_group_home_dir
innodb_log_arch_dir = /dr3/iblogs
innodb_log_archive=0
set-variable = innodb_log_files_in_group=3
# Die Log-Dateigröße auf ungefähr 15%
# der Puffer-Poolgröße setzen
set-variable = innodb_log_file_size=50M
set-variable = innodb_log_buffer_size=8M
# ..flush_log_at_trx_commit auf 0 setzen,
# wenn Sie es sich leisten können,
# ein paar der letzten Transaktionen zu verlieren
innodb_flush_log_at_trx_commit=1
set-variable = innodb_file_io_threads=4
set-variable = innodb_lock_wait_timeout=50
#innodb_flush_method=fdatasync
#innodb_fast_shutdown=1
#set-variable = innodb_thread_concurrency=5

Beachten Sie, dass die beiden Daten-Dateien auf unterschiedliche Platten platziert wurden. Der Grund für den Namen innodb_data_file_path ist, dass Sie auch Pfade zu Ihren Daten-Dateien angeben können und dass innodb_data_home_dir nur textlich mit Ihren Daten-Datei-Pfaden verkettet wird, wobei ein möglicher Schrägstrich oder Backslash dazwischen hinzugefügt wird. InnoDB füllt den Tabellenplatz (Tablespace), der durch die Daten-Dateien gebildet wird, von unten nach oben. In manchen Fällen verbessert es die Performance der Datenbank, wenn nicht alle Daten auf derselben physikalischen Festplatte platziert sind. Es verbessert häufig die Performance, Log-Dateien auf anderen Platten als die Daten zu platzieren.

Die Bedeutung der Konfigurationsparameter ist wie folgt:

OptionBeschreibung
innodb_data_home_dirDer allgemeine Teil des Verzeichnispfads für alle InnoDB-Daten-Dateien. Die Vorgabe für diesen Parameter ist das datadir von MySQL.
innodb_data_file_pathPfade zu individuellen Daten-Dateien und ihre Größen. Der volle Verzeichnispfad zu jeder Daten-Datei wird durch Verkettung von innodb_data_home_dir mit den hier angegebenen Pfaden hergestellt. Die Dateigrößen werden in Megabytes angegeben, daher das 'M' nach der obigen Angabe. InnoDB versteht auch die Abkürzung 'G', 1G bedeutet 1024M. Ab 3.23.44 können Sie die Dateigröße auf mehr als 4 GB setzen, wenn das Betriebssystem große Dateien unterstützt. Auf einige Betriebssystemen müssen Dateien kleiner als 2 GB sein. Die Summe der Dateigrößen muss mindestens 10 MB betragen.
innodb_mirrored_log_groupsAnzahl identischer Kopien von Log-Gruppen, die für die Datenbank gehalten werden. Momentan sollte dieser Parameter auf 1 gesetzt werden.
innodb_log_group_home_dirVerzeichnispfad zu den InnoDB-Log-Dateien.
innodb_log_files_in_groupAnzahl von Log-Dateien in der Log-Gruppe. InnoDB schreibt in zirkulärer Weise in die Dateien. Hier wird ein Wert 3 empfohlen.
innodb_log_file_sizeGröße jeder Log-Datei in einer Log-Gruppe in Megabytes. Sinnvolle Werte reichen von 1 MB bis 1/n-tel der Größe des Puffer-Pools, die unten angegeben wird, wobei n die Anzahl der Log-Dateien in der Gruppe ist. Je größer der Wert, desto weniger Checkpoint-Flush-Aktivität wird im Puffer benötigt, was Festplatten-Ein- und -Ausgaben erspart. Größere Log-Dateien bedeutet jedoch auch, dass die Wiederherstellung im Fall eines Absturzes langsamer ist. Die Gesamtgröße aller Log-Dateien muss auf 32-Bit-Computern kleiner als 4 GB sein.
innodb_log_buffer_sizeDie Größe des Puffers, den InnoDB benutzt, um in die Log-Dateien auf Platte zu schreiben. Sinnvolle Werte liegen im Bereich von 1 MB bis zur Hälfte der Gesamtgröße der Log-Dateien. Ein großer Log-Puffer erlaubt, dass große Transaktionen laufen können, ohne dass die Notwendigkeit besteht, das Log auf Platte zu schreiben, bis die Transaktion abgeschickt (commit) wird. Wenn Sie daher große Transaktionen haben, sparen Sie Festplatten-Ein- und Ausgaben, wenn Sie den Log-Puffer Groß machen.
innodb_flush_log_at_trx_commitNormalerweise wird dieser Parameter auf 1 gesetzt, was bedeutet, dass beim Abschicken (commit) einer Transaktion das Log auf Platte geschrieben wird (flush) und die durch die Transaktion gemachten Änderungen permanent werden und einen Datenbankabsturz überleben. Wenn Sie willens sind, in Bezug auf diese Sicherheit Kompromisse einzugeben und eher kleine Transaktionen laufen lassen, können Sie diesen Wert auf 0 setzen, um Festplatten-Ein- und -Ausgaben in Bezug auf die Log-Dateien zu verringern.
innodb_log_arch_dirDas Verzeichnis, in dem komplett geschriebene Log-Dateien archiviert werden, wenn Archivierung benutzt wird. Der Wert dieses Parameters sollte momentan derselbe sein wie innodb_log_group_home_dir.
innodb_log_archiveDieser Wert sollte momentan auf 0 gesetzt werden. Weil MySQL die Wiederherstellung aus einer Datensicherung unter Benutzung seiner eigenen Log-Dateien durchführt, gibt es momentan keine Notwendigkeit, InnoDB-Log-Dateien zu archivieren.
innodb_buffer_pool_sizeDie Größe des Speicherpuffers, den InnoDB benutzt, um Daten und Indexe seiner Tabellen zu cachen. Je größer Sie diesen Wert setzen, desto weniger Festplatten-Ein- und -Ausgaben werden für den Zugriff auf Daten in Tabellen benötigt. Auf einem dedizierten Datenbank-Server können Sie diesen Parameter auf bis zu 80% des physikalischen Arbeitsspeichers der Maschine setzen. Setzen Sie ihn allerdings nicht zu hoch, weil bei manchen Betriebssystemen der Wettbewerb um Arbeitsspeicher zu Paging führt.
innodb_additional_mem_pool_sizeDie Größe des Speicher-Pools, den InnoDB für die Speicherung von Daten-Wörterbuchinformationen und anderen internen Datenstrukturen benutzt. Ein sinnvoller Wert hierfür könnte 2 MB sein. Je mehr Tabellen Sie jedoch in Ihrer Applikation haben, desto mehr müssen Sie hier zuweisen. Wenn InnoDB in diesem Pool keinen Speicherplatz mehr hat, läßt es sich Speicherplatz vom Betriebssystem zuweisen und schreibt Warnmeldungen in die MySQL-Fehler-Log-Datei.
innodb_file_io_threadsDie Anzahl der Datei-Ein- und -Ausgabe-Threads in InnoDB. Normalerweise sollte dieser Wert 4 sein, aber Windows-Festplatten könnten von einer höheren Zahl profitieren.
innodb_lock_wait_timeoutTimeout in Sekunden. Solange wartet eine InnoDB-Transaktion auf eine Sperre, bevor sie abgebrochen (Rollback) wird. InnoDB erkennt automatisch Transaktionsblockierungen in seiner eigenen Sperr-Tabelle und bricht die Transaktion ab (Rollback). Wenn Sie den LOCK TABLES-Befehl oder andere transaktionssichere Tabellen-Handler als InnoDB in derselben Transaktion benutzen, kann eine Blockierung auftreten, die InnoDB nicht erkennen kann. In solchen Fällen ist ein Timeout nützlich, um die Situation zu bereinigen.
innodb_flush_method(Verfügbar ab Version 3.23.40.) Der Vorgabewert hierfür ist fdatasync. Ein andere Option ist O_DSYNC.

8.5.3. InnoDB-Tabellenplatz (Tablespace) erzeugen

Angenommen, Sie haben MySQL installiert und my.cnf so editiert, dass sie die notwendigen InnoDB Konfigurationsparameter enthält. Bevor Sie MySQL starten, sollten Sie überprüfen, dass die für InnoDB-Daten- und Log-Dateien angegebenen Verzeichnisse existieren und dass Sie auf diese Zugriffsrechte haben. InnoDB kann keine Verzeichnisse anlegen, nur Dateien. Überprüfen Sie auch, ob Sie auf der Festplatte genug Platz für Daten- und Log-Dateien haben.

Wenn Sie jetzt MySQL starten, fängt InnoDB an, Ihre Daten- und Log-Dateien zu erzeugen. InnoDB gibt dabei etwas wie das folgende aus:

~/mysqlm/sql > mysqld
InnoDB: The first specified data file /home/stefan/data/ibdata1 did not exist:
InnoDB: a new database to be created!
InnoDB: Setting file /home/stefan/data/ibdata1 size to 134217728
InnoDB: Database physically writes the file full: wait...
InnoDB: Data file /home/stefan/data/ibdata2 did not exist: new to be created
InnoDB: Setting file /home/stefan/data/ibdata2 size to 262144000
InnoDB: Database physically writes the file full: wait...
InnoDB: Log file /home/stefan/data/logs/ib_logfile0 did not exist: new to be created
InnoDB: Setting log file /home/stefan/data/logs/ib_logfile0 size to 5242880
InnoDB: Log file /home/stefan/data/logs/ib_logfile1 did not exist: new to be created
InnoDB: Setting log file /home/stefan/data/logs/ib_logfile1 size to 5242880
InnoDB: Log file /home/stefan/data/logs/ib_logfile2 did not exist: new to be created
InnoDB: Setting log file /home/stefan/data/logs/ib_logfile2 size to 5242880
InnoDB: Started
mysqld: ready for connections

Jetzt wurde eine neue InnoDB-Datenbank erzeugt. Sie können sich mit den üblichen MySQL-Client-Programmen wie mysql mit dem MySQL-Server verbinden. Wenn Sie den MySQL-Server mit mysqladmin shutdown herunter fahren, gibt InnoDB etwa wie das folgende aus:

010321 18:33:34  mysqld: Normal shutdown
010321 18:33:34  mysqld: Shutdown Complete
InnoDB: Starting shutdown...
InnoDB: Shutdown completed

Wenn Sie jetzt einen Blick auf die Daten-Dateien und Log-Verzeichnisse werfen, sehen Sie die erzeugten Dateien. Das Log-Verzeichnis enthält auch eine kleine Datei namens ib_arch_log_0000000000. Diese Datei resultiert aus der Datenbank-Erzeugung, nach der InnoDB die Log-Archivierung ausgeschaltet hat. Wenn MySQL noch einmal gestartet wird, sieht die Ausgabe etwa wie folgt aus:

~/mysqlm/sql > mysqld
InnoDB: Started
mysqld: ready for connections

8.5.3.1. Falls etwas bei der Datenbank-Erzeugung schiefgeht

Falls etwas bei der Datenbank-Erzeugung schiefgeht, sollten Sie alle durch InnoDB erzeugten Dateien löschen. Das heißt alle Daten-Dateien, alle Log-Dateien, die kleine archivierte Log-Datei und - falls Sie bereits InnoDB-Tabellen erzeugt haben, auch die entsprechenden .frm-Dateien für diese Tabellen in den MySQL-Datenbankverzeichnissen. Danach können Sie die InnoDB-Datenbankerzeugung erneut versuchen.

8.5.4. InnoDB-Tabellen erzeugen

Angenommen, Sie haben den MySQL-Client mit dem Befehl mysql test gestartet. Um eine Tabelle im InnoDB-Format zu erzeugen, müssen Sie im SQL-Befehl zur Tabellenerzeugung TYPE = InnoDB angeben:

CREATE TABLE kunde (A INT, B CHAR (20), INDEX (A)) TYPE = InnoDB;

Dieser SQL-Befehl erzeugt eine Tabelle und einen Index auf die Spalte A im InnoDB-Tabellenplatz (Tablespace), der aus den Daten-Dateien besteht, die Sie in my.cnf angegeben haben. MySQL erzeugt zusätzlich eine Datei kunde.frm im MySQL-Datenbankverzeichnis test. Intern fügt InnoDB seinem eigenen Datenwörterbuch einen Eintrag für die Tabelle 'test/kunde' hinzu. Wenn Sie daher eine Tabelle namens kunde in einer anderen Datenbank von MySQL erzeugen, kollidieren die Tabellennamen innerhalb InnoDB nicht.

Sie können den freien Speicherplatz im InnoDB-Tabellenplatz (Tablespace) mit dem Tabellen-Status-Befehl von MySQL für jede Tabelle, die Sie mit TYPE = InnoDB erzeugt haben, abfragen. Die Menge freien Platzes im Tabellenplatz (Tablespace) erscheint im Kommentar-Abschnitt der Tabelle in der Ausgabe von SHOW. Beispiel:

SHOW TABLE STATUS FROM test LIKE 'kunde'

Beachten Sie, dass die Statistiken, die SHOW über InnoDB-Tabellen ausgibt, nur Näherungswerte sind: Sie werden für die SQL-Optimierung benutzt. Die für Tabelle und Indexe reservierten Größen in Bytes sind allerdings genau.

8.5.4.1. MyISAM-Tabellen in InnoDB-Tabellen umwandeln

InnoDB hat keine spezielle Optimierung für separate Index-Erzeugung. Daher lohnt es sich nicht, die Tabelle zu exportieren und importieren und die Indexe danach zu erzeugen. Die schnellste Art, eine Tabelle in InnoDB zu ändern, ist, die Einfügungen direkt in eine InnoDB-Tabelle vorzunehmen, das heißt, ALTER TABLE ... TYPE=INNODB zu benutzen oder eine leere InnoDB-Tabelle mit identischen Definitionen zu nehmen und die Zeilen mit INSERT INTO ... SELECT * FROM ... einzufügen.

Um eine bessere Kontrolle über den Einfügeprozess zu erhalten, kann es besser sein, große Tabellen in Teilstücken einzufügen:

INSERT INTO neue_tabelle SELECT * FROM alte_tabelle WHERE schluessel > etwas
                                             AND schluessel <= etwas_anderes;

Nachdem alle Daten eingefügt wurden, können Sie die Tabellen umbenennen.

Während der Umwandlung großer Tabellen sollten Sie den InnoDB-Puffer-Pool hoch setzen, um Festplatten-Ein- und -Ausgaben zu verringern, allerdings nicht höher als 80% des physikalischen Arbeitsspeichers. Sie sollten die InnoDB-Log-Dateien Groß machen und auch den Log-Puffer.

Stellen Sie sicher, dass Sie genug Tabellenplatz (Tablespace) haben! InnoDB-Tabellen benötigen viel mehr Platz als MyISAM-Tabellen. Wenn ein ALTER TABLE nicht mehr genug Platz hat, wird ein Rollback gestartet, das Stunden dauern kann, wenn es auf der Festplatte stattfindet. Bei Einfügeoperationen verwendet InnoDB den Einfügepuffer, um sekundäre Index-Datensätze mit Indexen in Stapeln zu vermischen. Das spart eine Menge an Festplatten-Ein- und -Ausgaben. Beim Rollback wird kein solcher Mechanismus benutzt, weshalb das Rollback bis zu 30 mal länger als das Einfügen dauern kann.

Falls Sie keine wertvollen Daten in Ihren InnoDB-Dateien haben, ist es im Fall eines 'festgefahrenen' Rollback besser, den Datenbank-Prozess zu killen und alle InnoDB-Daten- und Log-Dateien sowie alle InnoDB-Tabellen (.frm-Dateien) zu löschen und noch einmal anzufangen, statt darauf zu warten, dass Millionen von Festplatten-Ein- und -Ausgaben beendet werden.

8.5.4.2. Fremdschlüssel-(Foreign Key)-Beschränkungen

InnoDB-Version 3.23.44 hat Fremdschlüssel-(Foreign Key)-Beschränkungen. InnoDB ist der erste MySQL-Tabellentyp, der die Definition von Fremdschlüssel-Beschränkungen zuläßt, um die Integrität Ihrer Daten zu überwachen.

Die Syntax einer Fremdschlüsseldefinition in InnoDB:

FOREIGN KEY (index_spalten_name, ...) REFERENCES tabellen_name (index_spalten_name, ...)

Beispiel:

CREATE TABLE eltern(id INT NOT NULL, PRIMARY KEY (id)) TYPE=INNODB;
CREATE TABLE kind(id INT, eltern_id INT, INDEX par_ind (eltern_id),
           FOREIGN KEY (eltern_id) REFERENCES eltern(id)) TYPE=INNODB;

Beide Tabellen müssen vom Typ InnoDB sein und es muss einen Index geben, bei dem der Fremdschlüssel und der referenzierte Schlüssel als erste Spalten aufgeführt sind. Jegliches ALTER TABLE entfernt momentan alle Fremdschlüsselbeschränkungen, die für die Tabelle definiert wurden, aber nicht die Beschränkungen, die die Tabelle referenzieren. Korrespondierende Spalten im Fremdschlüssel und dem referenzierten Schlüssel müssen ähnliche interne Datentypen innerhalb InnoDB sein, so dass sie ohne Typumwandlung verglichen werden können. Die Längen von Zeichenkettentypen müssen nicht dieselben sein. Die Größe und Vorzeichen / kein Vorzeichen von Ganzzahltypen müssen dieselben sein.

Beim Prüfen von Fremdschlüsseln setzt InnoDB gemeinsame Sperren auf Zeilenebene auf kind- und eltern-Datensätze, die es betrachten muss. InnoDB prüft Fremdschlüssel-(Foreign Key)-Beschränkungen sofort: Die Prüfung wird nicht bis zu einem Transaktions-Commit verschoben.

InnoDB läßt zu, dass jegliche Tabelle gelöscht wird, selbst wenn das die Fremdschlüssel-(Foreign Key)-Beschränkungen durchbrechen würde, die die Tabelle referenzieren. Wenn Sie eine Tabelle löschen, werden die Beschränkungen, die in ihrem CREATE-Statement definiert wurden, ebenfalls gelöscht.

Wenn Sie eine gelöschte Tabelle neu erzeugen, muss sie eine Definition haben, die mit den Fremdschlüssel-(Foreign Key)-Beschränkungen konform ist, die sie referenzieren. Sie muss die richten Spaltennamen und -typen haben, und sie muss - wie oben angegeben - Indexe auf die referenzierten Schlüssel haben.

Sie können die Fremdschlüssel-(Foreign Key)-Beschränkungen für eine Tabelle wie folgt auflisten: T with

SHOW TABLE STATUS FROM ihr_datenbank_name LIKE 'T';

Die Fremdschlüssel-(Foreign Key)-Beschränkungen werden im Tabellen-Kommentar der Ausgabe aufgelistet.

InnoDB unterstützt noch kein CASCADE ON DELETE oder andere spezielle Optionen für diese Beschränkungen.

8.5.5. Hinzufügen und Entfernen von InnoDB-Daten- und -Log-Dateien

Sie können die Größe einer InnoDB-Daten-Datei nicht vergrößern. Um Ihrem Tabellenplatz (Tablespace) mehr hinzuzufügen, müssen Sie eine neue Daten-Datei hinzufügen. Um das zu tun, müssen Sie Ihre MySQL-Datenbank herunter fahren, die my.cnf-Datei editieren und eine neue Datei zu innodb_data_file_path hinzufügen. Dann starten Sie MySQL erneut.

Momentan können Sie keine Daten-Datei aus InnoDB entfernen. Um die Größe Ihrer Datenbank zu verringern, müssen Sie mysqldump benutzen, um alle Ihre Tabellen zu dumpen, eine neue Datenbank erzeugen und Ihre Tabellen in die neue Datenbank importieren.

Wenn Sie die Anzahl oder die Größe Ihrer InnoDB-Log-Dateien ändern wollen, müssen Sie MySQL herunter fahren und sicher stellen, dass er ohne Fehler herunter fuhr. Dann kopieren Sie die alten Log-Dateien an eine sichere Stelle, falls etwas beim Herunterfahren schiefging und Sie die Datenbank wiederherstellen müssen. Löschen Sie die alten Log-Dateien aus dem Log-Datei-Verzeichnis, editieren Sie my.cnf und starten Sie MySQL noch einmal. InnoDB meldet beim Starten, dass es neue Log-Dateien anlegt.

8.5.6. Datensicherung und Wiederherstellung einer InnoDB-Datenbank

Der Schlüssel zur sicheren Datenbankverwaltung sind regelmäßige Datensicherungen. Im eine 'binäre' Sicherung Ihrer Datenbank zu machen, tun Sie folgendes:

  • Fahren Sie Ihre MySQL-Datenbank herunter und stellen Sie sicher, dass dabei keine Fehler auftraten.

  • Kopieren Sie Ihre Daten-Dateien an eine sichere Stelle.

  • Kopieren Sie alle InnoDB-Log-Dateien an eine sichere Stelle.

  • Kopieren Sie Ihre my.cnf Konfigurationsdatei(en) an eine sichere Stelle.

  • Kopieren Sie alle .frm-Dateien für Ihre InnoDB-Tabellen an eine sichere Stelle.

Momentan gibt es kein Online- oder inkrementelles Datensicherungsprogramm für InnoDB, obwohl diese auf der TODO-Liste sind.

Zusätzlich zu den beschriebenen Binär-Datensicherungen sollten Sie ausserdem regelmäßig Dumps Ihrer Tabellen mit mysqldump machen. Der Grund ist, dass eine Binärdatei beschädigt sein kann, ohne dass Sie das bemerken. Gedumpte Tabellen werden in Textdateien gespeichert, die Menschen-lesbar und viel einfacher als binäre Datenbankdateien sind. Aus gedumpten Dateien läßt sich Tabellenbeschädigung leichter erkennen und da ihr Format einfacher ist, ist das Risiko ernsthafter Datenbeschädigung in ihnen geringer.

Es ist eine gute Idee, Dumps zur gleichen Zeit zu machen wie die binäre Datensicherung Ihrer Datenbank. Sie müssen alle Clients aus Ihrer Datenbank ausschließen, um konsistente Schnappschüsse aller Ihrer Tabellen im Dump zu bekommen. Danach können Sie die binäre Datensicherung machen, so dass Sie einen konsistenten Schnappschuss Ihrer Datenbank in zwei Formaten haben.

Um in der Lage zu sein, Ihre InnoDB-Datenbank aus den beschriebenen binären Datensicherungen wiederherzustellen, müssen Sie Ihre MySQL-Datenbank mit allgemeinem Loggen und angeschalteter Log-Archivierung von MySQL laufen lassen. Mit allgemeinem Loggen ist hier der Log-Mechanismus des MySQL-Servers gemeint, der unabhängig von den InnoDB-Logs ist.

Zum Wiederherstellen nach einem Absturz des MySQL-Serverprozesses ist es lediglich nötig, diesen erneut zu starten. InnoDB prüft automatisch die Log-Dateien und führt ein Roll-Forward der Datenbank bis zum aktuellen Stand durch. InnoDB macht ein automatisches Rollback nicht abgeschlossener (committed) Transaktionen, die zur Zeit des Absturzes anhängig waren. Während der Wiederherstellung gibt InnoDB etwa folgendes aus:

~/mysqlm/sql > mysqld
InnoDB: Database was not shut down normally.
InnoDB: Starting recovery from log files...
InnoDB: Starting log scan based on checkpoint at
InnoDB: log sequence number 0 13674004
InnoDB: Doing recovery: scanned up to log sequence number 0 13739520
InnoDB: Doing recovery: scanned up to log sequence number 0 13805056
InnoDB: Doing recovery: scanned up to log sequence number 0 13870592
InnoDB: Doing recovery: scanned up to log sequence number 0 13936128
...
InnoDB: Doing recovery: scanned up to log sequence number 0 20555264
InnoDB: Doing recovery: scanned up to log sequence number 0 20620800
InnoDB: Doing recovery: scanned up to log sequence number 0 20664692
InnoDB: 1 uncommitted transaction(s) which must be rolled back
InnoDB: Starting rollback of uncommitted transactions
InnoDB: Rolling back trx no 16745
InnoDB: Rolling back of trx no 16745 completed
InnoDB: Rollback of uncommitted transactions completed
InnoDB: Starting an apply batch of log records to the database...
InnoDB: Apply batch completed
InnoDB: Started
mysqld: ready for connections

Wenn Ihre Datenbank beschädigt wird oder Ihre Festplatte Fehler hat, müssen Sie eine Wiederherstellung aus einer Datensicherung durchführen. Im Falle der Beschädigung sollten Sie zunächst eine Datensicherung finden, die nicht beschädigt ist. Machen Sie aus der Datensicherung eine Wiederherstellung aus den allgemeinen Log-Dateien von MySQL unter Beachtung der Anleitungen im MySQL-Handbuch.

8.5.6.1. Checkpoints

InnoDB hat einen Checkpoint-Mechanismus implementiert, der sich Fuzzy Checkpoint nennt. InnoDB schreibt veränderten Datenbankseiten aus dem Puffer-Pool in kleinen Stapeln (Batch) auf Platte (flush), daher besteht keine Notwendigkeit, den Puffer-Pool in einem einzelnen Stapel zurückzuschreiben, was in der Praxis dazu führen würde, dass SQL-Statements von Benutzern für eine Weile angehalten würden.

Bei der Reparatur nach Abstürzen sucht InnoDB nach einem Checkpoint-Label in den Log-Dateien. Es weiß, dass alle Änderungen an der Datenbank vor dem Label bereits im Platten-Image der Datenbank enthalten sind. InnoDB scannt anschließend die Log-Dateien ab dem Checkpoint vorwärts und wendet die geloggten Änderungen auf die Datenbank an.

InnoDB schreibt in zirkulärer Art in die Log-Dateien. Alle abgeschickten (committed) Änderungen, die dazu führen, dass sich die Datenbankseiten im Puffer-Pool vom Image auf der Platte unterscheiden, müssen in den Log-Dateien verfügbar sein, für den Fall, dass InnoDB eine Wiederherstellung durchführen muss. Das heißt, wenn InnoDB anfängt, eine Log-Datei auf zirkuläre Weise wieder zu benutzen, muss es sicherstellen, dass die Datenbankseiten-Images auf der Festplatte bereits die Änderungen enthalten, die in der Log-Datei mitgeschrieben sind, die InnoDB benutzen wird. Mit anderen Worten muss InnoDB einen Checkpoint machen, was oft das Zurückschreiben auf Platte (flush) geänderter Datenbankseiten beinhaltet.

Das erklärt, warum es Festplatten-Ein- und -Ausgaben sparen kann, wenn man die Log-Dateien sehr Groß macht. Es kann sinnvoll sein, die Gesamtgröße der Log-Dateien so Groß wie den Puffer-Pool oder sogar noch größer zu machen. Der Nachteil großer Log-Dateien ist, dass eine Reparatur nach Absturz länger dauern kann, weil mehr Log-Einträge auf die Datenbank angewendet werden müssen.

8.5.7. Eine InnoDB-Datenbank auf eine andere Maschine verschieben

InnoDB-Daten- und Log-Dateien sind auf allen Plattformen binärkompatibel, wenn das Fließkommazahlenformat auf den Maschinen dasselbe ist. Sie können eine InnoDB-Datenbank einfach verschieben, indem Sie alle relevanten Dateien kopieren, die im vorherigen Abschnitt über Datensicherung erwähnt wurden. Wenn sich das Fließkommaformat auf den Maschinen unterscheidet, sie aber keine FLOAT- oder DOUBLE-Datentypen in Ihren Tabellen benutzt haben, ist die Prozedur dieselbe: Kopieren Sie einfach die relevanten Dateien. Wenn die Formate unterschiedlich sind und Ihre Tabellen Fließkomma-Daten enthalten, müssen Sie mysqldump und mysqlimport benutzen, um diese Tabellen zu verschieben.

Ein Tipp zur Performance: Schalten Sie Auto-Commit aus, wenn Sie Daten in Ihre Datenbank importieren (unter der Annahme, dass Ihr Tabellenplatz (Tablespace) genug Platz für das große Rollback-Segment enthält, den die große Import-Transaktion erzeugen wird). Machen Sie das Commit erst nach dem Import einer ganzen Tabelle oder eines Segments einer Tabelle.

8.5.8. InnoDB-Transaktionsmodell

Im InnoDB-Transaktionsmodell war das Ziel, die besten Eigenschaften einer multiversionsfähigen Datenbank mit dem traditionellen Zwei-Phasen-Sperren zu verbinden. InnoDB führt Sperren auf Zeilenebene durch und läßt Anfragen vorgabemäßig als nicht sperrende konsistente Leseoperationen laufen, im Stil von Oracle. Das Tabellensperren ist in InnoDB so platzsparend gespeichert, dass keine Sperr-Eskalation benötigt wird: Typischerweise dürfen mehrere Benutzer jede Zeile in der Datenbank oder eine beliebige Teilmenge der Zeilen sperren, ohne dass InnoDB keinen Speicher mehr hat.

Bei InnoDB findet jede Benutzeraktivität innerhalb von Transaktionen statt. Wenn der Auto-Commit-Modus in MySQL benutzt wird, stellt jedes SQL-Statement eine einzelne Transaktion dar. Wenn der Auto-Commit-Modus ausgeschaltet wird, kann man sich vorstellen, dass ein Benutzer stets eine Transaktion offen hat. Wenn er das SQL-COMMIT- oder ROLLBACK-Statement absetzt, beendet das die aktuelle Transaktion und eine neue beginnt. Beide Statements heben alle InnoDB-Sperren auf, die während der aktuellen Transaktion gesetzt wurden. Ein COMMIT bedeutet, dass die in der aktuellen Transaktion gemachten Änderungen permanent und sichtbar für andere Benutzer gemacht werden. Auf der anderen Seite bricht ein ROLLBACK alle Änderungen ab, die in der aktuellen Transaktion gemacht wurden.

8.5.8.1. Konsistentes Lesen

Konsistentes Lesen bedeutet, dass InnoDB seine Multiversionsfähigkeiten nutzt, um einer Anfrage einen Schnappschuss der Datenbank zu einem bestimmten Zeitpunkt zu zeigen. Die Anfrage sieht genau die Änderungen, die von Transaktionen durchgeführt wurden, die bis zu diesem Zeitpunkt abgeschlossen wurden (committed), und keine Änderungen, die später gemacht wurden oder die noch nicht abgeschlossen sind. Die Ausnahme von der Regel ist, dass die Anfrage die Änderungen sieht, die durch die Transaktion selbst durchgeführt wurde, die die Anfrage absetzt.

Wenn eine Transaktion ihr erstes Konsistentes Lesen durchführt, weist InnoDB den Schnappschuss oder Zeitpunkt zu, den jedes Konsistente Lesen in derselben Transaktion benutzen wird. Im Schnappschuss sind alle Transaktionen enthalten, die vor der Zuweisung zum Schnappschuss abgeschlossen (committed) wurden. Daher ist Konsistentes Lesens innerhalb derselben Transaktion auch untereinander konsistent. Sie können einen frischeren Schnappschuss für Ihre Anfragen erhalten, indem Sie die aktuelle Transaktion beenden (commit) und danach neue Anfragen absetzen.

Konsistentes Lesen ist der vorgabemäßige Modus, in dem InnoDB SELECT-Statements abarbeitet. Konsistentes Lesen setzt keinerlei Sperren auf die Tabellen, auf die es zugreift. Daher können andere Benutzer zur selben Zeit, wie Konsistentes Lesen auf die Tabelle durchgeführt wird, diese verändern.

8.5.8.2. Lesevorgänge sperren

Unter manchen Umständen ist Konsistentes Lesen nicht wünschenswert. Angenommen, Sie wollen eine neue Zeile in die Tabelle kind einfügen und dabei sicherstellen, dass das Kind bereits Eltern in der Tabelle eltern hat.

Wenn Sie Konsistentes Lesen benutzen, um die Tabelle eltern zu lesen und in der Tat die Eltern des Kindes in der Tabelle sehen, können Sie dann sicher die Kind-Zeile zur Tabelle kind hinzufügen? Nein, denn es kann sein, dass zwischenzeitlich jemand anderes die Eltern-Zeile aus der Tabelle eltern gelöscht hat und Sie das nicht sehen.

Die Lösung besteht darin, das SELECT im Sperrmodus durchzuführen. LOCK IN SHARE MODE.

SELECT * FROM eltern WHERE NAME = 'Hinz' LOCK IN SHARE MODE;

Wenn Sie ein Lesen im Share-Modus durchführen, heißt das, dass die letzten verfügbaren Daten gelesen werden und eine Shared-Modus-Sperre auf die Zeile gesetzt wird, die gelesen wird. Wenn die letzten Daten zu einer noch nicht abgeschlossenen Transaktion eines anderen Benutzers gehören, wird gewartet, bis die Transaktion abgeschlossen (committed) ist. Eine Shared-Modus-Sperre verhindert, dass andere die Zeile aktualisieren oder löschen, die gerade gelesen wurde. Nachdem festgestellt wurde, dass die obige Anfrage die Eltern 'Hinr' zurückgibt, kann das Kind sicher zur Tabelle kind hinzugefügt und die Transaktion abgeschlossen werden. Dieses Beispiel zeigt, wie Sie in Ihren Applikations-Code referentielle Integrität integrieren können.

Sehen wir uns ein weiteres Beispiel an. Wir haben ein ganzzahliges Zählerfeld in einer Tabelle kind_codes, was benutzt wird, um jedem Kinde, das wir der Tabelle kind hinzufügen, eine eindeutige Kennung zuzuweisen. Es ist offensichtlich, dass Konsistentes Lesen oder Shared-Modus-Lesen kein geeignetes Mittel ist, um den aktuellen Wert des Zählers zu ermitteln, weil nämlich zwei Benutzer der Datenbank denselben Wert des Zählers sehen können und wir daher einen Fehler wegen doppelter Schlüsseleinträge erhalten, wenn wir zwei Kinder mit derselben Kennung in die Tabelle einfügen.

In diesem Fall gibt es zwei geeignete Möglichkeiten, das Lesen und Heraufzählen des Zählers zu implementieren: (1) Zuerst den Zähler um eins erhöhen und erst danach lesen. (2) Zuerst den Zähler im Sperr-Modus FOR UPDATE lesen und danach heraufzählen:

SELECT COUNTER_FIELD FROM kind_codes FOR UPDATE;
UPDATE kind_codes SET COUNTER_FIELD = COUNTER_FIELD + 1;

SELECT ... FOR UPDATE liest die letzten verfügbaren Daten und setzt exklusive Sperren auf jede Zeile, die es liest. Daher setzt es dieselben Sperren, die ein gesuchtes SQL-UPDATE auf die Zeilen setzen würde.

8.5.8.3. Nächsten Schlüssel sperren: Wie das Phantom-Problem vermieden wird

Beim Sperren auf Zeilenebene benutzt InnoDB einen Algorithmus, der Nächsten-Schlüssel-Sperren genannt wird. InnoDB führt das Sperren auf Zeilenebene so durch, dass es beim Suchen oder Scannen eines Indexes auf eine Tabelle gemeinsam genutzte (shared) oder exklusive Sperren auf die Index-Datensätze setzt, die es findet. Daher werden die Sperren auf Zeilenebene genauer Index-Datensatz-Sperren genannt.

Die Sperren, die InnoDB auf Index-Datensätze setzt, betreffen auch die 'Lücke' vor diesem Index-Datensatz. Wenn ein Benutzer eine gemeinsam benutzte (shared) oder exklusive Sperre auf den Datensatz R in einem Index hat, kann ein anderen Benutzer keinen Datensatz direkt vor R (in der Index-Reihenfolge) einfügen. Dieses Sperren von Lücken wird durchgeführt, um das so genannte Phantom-Problem zu vermeiden. Angenommen, man will alle Kinder aus der Tabelle kind lesen und sperren, die eine Kennung größer 100 haben, und irgend ein Feld in der ausgewählten Zeile aktualisieren:

SELECT * FROM kind WHERE ID > 100 FOR UPDATE;

Angenommen, es gibt einen Index auf der Tabelle kind auf der Spalte ID. Unsere Anfrage scannt diesen Index ab dem ersten Datensatz, bei dem ID größer als 100 ist. Wenn jetzt die auf den Index-Datensatz gesetzten Sperren nicht Einfügeoperationen sperren würden, die in die Lücken ausgeführt würden, könnte zwischenzeitlich ein neues Kind in die Tabelle eingefügt werden. Wenn jetzt unsere Transaktion noch einmal folgendes ausführen würde:

SELECT * FROM kind WHERE ID > 100 FOR UPDATE;

Sehen wir ein neues Kind in der Ergebnismenge, die die Anfrage zurückgibt. Das verstößt gegen das Isolationsprinzip von Transaktionen: Eine Transaktion sollte in der Lage sein, so abzulaufen, dass die Daten, die sie gelesen hat, sich nicht während der Transaktion ändern. Wenn wir einen Satz von Zeilen als Daten-Posten betrachten, würde das neue 'Phantom'-Kind dieses Isolationsprinzip durchbrechen.

Wenn InnoDB einen Index scannt, kann es auch die Lücke nach dem letzten Datensatz im Index sperren. Genau das passiert im vorherigen Beispiel: Die Sperren, die von InnoDB gesetzt werden, verhindert jedes Einfügen in die Tabelle an Stellen, wo ID größer als 100 ist.

Sie können Nächsten-Schlüssel-Sperren dazu benutzen, eine Eindeutigkeitsprüfung in Ihre Applikation zu implementieren: Wenn Sie Ihre Daten im Share-Modus lesen und kein Duplikat für eine Zeile sehen, die Sie einfügen werden, können Sie Ihre Zeile sicher einfügen und wissen, dass das Nächsten-Schlüssel-Sperren verhindern wird, dass zwischenzeitlich jemand eine Duplikatzeile Ihrer Zeile einfügt. Daher gestattet Ihnen das Nächsten-Schlüssel-Sperren, die Nicht-Existenz von irgend etwas in Ihrer Tabelle zu 'sperren'.

8.5.8.4. Sperren, die in InnoDB durch unterschiedliche SQL-Statements gesetzt werden

  • SELECT ... FROM ... : Das ist Konsistentes Lesen, es wird ein Schnappschuss einer Datenbank gelesen und es werden keine Sperren gesetzt.

  • SELECT ... FROM ... LOCK IN SHARE MODE : setzt gemeinsam genutztes (shared) Nächsten-Schlüssel-Sperren auf alle Index-Datensätze, die beim Lesen gefunden werden.

  • SELECT ... FROM ... FOR UPDATE : setzt exklusives Nächsten-Schlüssel-Sperren auf alle Index-Datensätze, die beim Lesen gefunden werden.

  • INSERT INTO ... VALUES (...) : setzt eine exklusive Sperre auf die eingefügte Zeile. Beachten Sie, dass diese Sperre kein Nächsten-Schlüssel-Sperren ist und andere Benutzer nicht davon abhält, etwas in die Lücke vor der eingefügten Zeile einzufügen. Wenn ein Fehler wegen doppelter Schlüsseleinträge auftritt, setzt dieser Befehl eine gemeinsam genutzte (shared) Sperre auf den doppelten (Duplikat) Index-Datensatz.

  • INSERT INTO T SELECT ... FROM S WHERE ... setzt eine exklusive Sperre (kein Nächsten-Schlüssel-Sperren) auf jede Zeile, die in T eingefügt wurde. Sucht nach S in Form von Konsistentem Lesen, aber setzt Nächsten-Schlüssel-Sperren auf S, wenn bei MySQL das Loggen angeschaltet ist. InnoDB muss in letzterem Fall Sperren setzen, weil bei einer Roll-Forward-Wiederherstellung aus einer Datensicherung jedes SQL-Statement auf genau dieselbe Weise ausgeführt werden muss, wie es ursprünglich ausgeführt wurde.

  • CREATE TABLE ... SELECT ... führt SELECT als Konsistentes Lesen oder mit gemeinsam genutzten (shared) Sperren aus, wie im vorherigen Punkt.

  • REPLACE wird wie Einfügen ausgeführt, wenn es keine Kollision auf einem eindeutigen Schlüssel gibt. Ansonsten wird ein exklusives Nächsten-Schlüssel-Sperren auf die Reihe gesetzt, die aktualisiert werden muss.

  • UPDATE ... SET ... WHERE ... setzt ein exklusives Nächsten-Schlüssel-Sperren auf jeden Datensatz, der beim Suchen gefunden wird.

  • DELETE FROM ... WHERE ... setzt ein exklusives Nächsten-Schlüssel-Sperren auf jeden Datensatz, der beim Suchen gefunden wird.

  • Wenn auf der Tabelle eine FOREIGN KEY-Beschränkung definiert ist, setzt jedes Einfügen, Aktualisieren oder Löschen, was die Überprüfung der Beschränkungsbedingung erfordert, gemeinsam genutzte (shared) Sperren auf Datensatzebene auf die Datensätze, die bei der Überprüfung der Beschränkung betrachtet werden. Auch im Falle, dass die Beschränkung fehlschlägt, setzt InnoDB diese Sperren.

  • LOCK TABLES ... : setzt Tabellensperren. In der Implementation setzt die MySQL-Ebene des Codes diese Sperren. Die automatische Blockierungserkennung von InnoDB kann keine Blockierungen bemerken, bei denen solche Tabellensperren involviert sind, siehe nächster Abschnitt weiter unten. Sehen Sie auch im Abschnitt 13 ('InnoDB-Einschränkungen') wegen folgendem nach: Weil MySQL keine Sperren auf Zeilenebene erkennt, ist es möglich, dass Sie eine Sperre auf eine Tabelle erhalten, auf der ein anderer Benutzer momentan Sperren auf Zeilenebene hat. Das gefährdet allerdings nicht die Transaktionsintegrität.

8.5.8.5. Blockierungserkennung und Rollback

InnoDB erkennt automatisch eine Blockierung von Transaktionen und rollt die Transaktion zurück, deren Sperranforderung diejenige war, die die Blockierung aufbaute, also einen Kreis im Warte-Diagramm von Transaktionen. InnoDB kann keine Blockierungen erkennen, bei denen eine Sperre im Spiel ist, die durch ein MySQL-LOCK TABLES-Statement verursacht wurde, oder wenn eine Sperre durch einen anderen Tabellen-Handler als InnoDB gesetzt wurde. Solche Situationen müssen Sie mit innodb_lock_wait_timeout, das in my.cnf gesetzt wird.

Wenn InnoDB ein komplettes Rollback einer Transaktion durchführt, werden alle Sperren der Transaktion aufgehoben. Wenn jedoch nur ein einzelnes SQL-Statement als Ergebnis eines Fehlers zurückgerollt wird, können einige der Sperren, die durch das SQL-Statement gesetzt wurde, verbleiben. Das liegt daran, dass InnoDB Zeilensperren in einem Format speichert, die ihm unmöglich machen, im Nachhinein zu erkennen, welche Sperre durch welches SQL-Statement gesetzt wurde.

8.5.8.6. Ein Beispiel, wie konsistentes Lesen bei InnoDB funktioniert

Wenn Sie ein Konsistentes Lesen ausführen, also ein gewöhnliches SELECT-Statement, gibt InnoDB Ihrer Transaktion einen Zeitpunkt (Timepoint), gemäß dem Ihre Anfrage die Datenbank sieht. Wenn daher Transaktion B eine Zeile löscht und das wirksam wird (commit), nachdem Ihr Zeitpunkt zugewiesen wurde, werden Sie die Zeile nicht als gelöscht sehen. Gleiches gilt für Einfüge- und Aktualisierungsoperationen.

Sie können Ihren Zeitpunkt 'vorstellen', indem Sie Ihre Transaktion abschicken (commit) und dann ein weiteres SELECT ausführen.

Das nennt sich Multiversioned Concurrency Control (multiversionierte Gleichzeitigkeitskontrolle):

                  Benutzer A             Benutzer B

              set autocommit=0;      set autocommit=0;
zeit
|             SELECT * FROM t;
|             empty set
|                                    INSERT INTO t VALUES (1, 2);
|
v             SELECT * FROM t;
              empty set
                                     COMMIT;

              SELECT * FROM t;
              empty set;

              COMMIT;

              SELECT * FROM t;
              ---------------------
              |    1    |    2    |
              ---------------------

Daher sieht Benutzer A die durch B eingefügte Zeile erst, wenn B das Einfügen und A seine eigene Transaktion abgeschickt hat (commit), so dass der Zeitpunkt hinter das Commit von B 'vorgestellt' ist.

Wenn Sie den 'frischsten' Zustand der Datenbank sehen wollen, sollten Sie ein sperrendes Lesen (Locking Read) benutzen:

SELECT * FROM t LOCK IN SHARE MODE;

8.5.9. Tipps zur Performance-Steigerung

1. Wenn das Unix-top oder der Windows-Task-Manager zeigen, dass die CPU-Auslastung weniger als 70% beträgt, ist Ihre Auslastung wahrscheinlich Platten-gebunden. Das kann daran liegen, dass Sie zu viele Transaktionen abschicken (commit) oder dass der Puffer-Pool zu klein ist. Dann kann es helfen, den Puffer-Pool zu vergrößern. Setzen Sie ihn aber nicht höher als 80% des physikalischen Arbeitsspeichers.

2. Packen Sie mehrere Änderungen in eine Transaktion. InnoDB muss das Log jedes Mal auf Platte zurückschreiben (flush), wenn eine Transaktion abgeschickt wird (commit), wenn diese Transaktion irgend welche Änderungen an der Datenbank vorgenommen hat. Weil die Rotationsgeschwindigkeit einer Platte typischerweise höchsten 167 Umdrehungen pro Sekunde beträgt, beschränkt das die Anzahl von Commits auf eben diese Zahl pro Sekunde, wenn die Festplatte nicht das Betriebssystem täuscht.

3. Wenn Sie es sich leisten können, einige der zuletzt abgeschickten (committed) Transaktionen zu verlieren, können Sie den my.cnf-Parameter innodb_flush_log_at_trx_commit auf 0 setzen. InnoDB versucht dann trotzdem, das Log einmal pro Sekunde auf Platte zurückzuschreiben (flush), doch dieses Zurückschreiben ist nicht garantiert.

4. Machen Sie Ihre Log-Dateien Groß, selbst so Groß wie den Puffer-Pool. Wenn InnoDB seine Log-Dateien vollgeschrieben hat, muss es die veränderten Inhalte des Puffer-Pools in einem Checkpoint auf Platte schreiben. Kleine Log-Dateien verursachen daher unnötige Festplatten-Schreibzugriffe. Der Nachteil großer Log-Dateien liegt darin, dass die Wiederherstellungszeit länger wird.

5. Ausserdem sollte der Log-Puffer recht Groß sein, sagen wir 8 MB.

6. (Relevant from 3.23.39 up.) In einigen Versionen von Linux und Unix ist das Zurückschreiben von Dateien auf Platte (flush) mit dem Unix-fdatasync und anderen ähnlichen Methoden überraschend langsam. InnoDB benutzt vorgabemäßig die fdatasync-Funktion. Wenn Sie mit der Datenbank-Schreib-Performance nicht zufrieden sind, können Sie versuchen, die innodb_flush_method in my.cnf auf O_DSYNC zu setzen, obwohl O_DSYNC auf den meisten Systemen langsamer zu sein scheint.

7. Wenn Sie Daten in InnoDB importieren, stellen Sie sicher, dass MySQL autocommit=1 nicht angeschaltet hat, denn dann benötigt jedes Einfügen ein Zurückschreiben des Logs auf Platte (flush). Setzen Sie vor Ihre SQL-Importdatei die Zeile

set autocommit=0;

und danach

commit;

Wenn Sie die mysqldump-Option --opt benutzen, erhalten Sie Dump-Dateien, die sich sehr schnell auch in eine InnoDB-Tabelle importieren lassen, selbst ohne sie in die oben erwähnten set autocommit=0; ... commit;-Wrapper zu verpacken.

8. Hüten Sie sich vor großen Rollbacks beim Einfügen von Massendaten: InnoDB benutzt den Einfüge-Puffer, um beim Einfügen Festplatten-Ein- und -Ausgaben zu sparen, doch beim entsprechenden Rollback wird kein solcher Mechanismus benutzt. Ein Festplatten-gebundenes Rollback kann die 30-fache Zeit des entsprechenden Einfügevorgangs in Anspruch nehmen. Es hilft nicht, den Datenbankprozess zu killen, weil der Rollback erneut starten wird, wenn die Datenbank hochfährt. Die einzige Möglichkeit, ein aus dem Ruder gelaufenes Rollback loszuwerden, besteht darin, den Puffer-Pool zu erhöhen, so dass das Rollback CPU-gebunden wird und damit schnell läuft, oder indem die gesamte InnoDB-Datenbank gelöscht wird.

9. Seien Sie auch vor anderen großen Festplatten-gebundenen Operationen auf der Hut. Benutzen Sie DROP TABLE oder TRUNCATE (ab MySQL-4.0), um eine Tabelle zu löschen, nicht DELETE FROM tabelle.

10. Benutzen Sie das mehrzeilige INSERT, um den Kommunikations-Overhead zwischen Client und Server zu verringern, wenn Sie viele Zeilen einfügen müssen:

INSERT INTO tabelle VALUES (1, 2), (5, 5);

Dieser Tipp gilt natürlich für jeden Tabellentyp, nicht nur für InnoDB.

8.5.9.1. Der InnoDB-Monitor

Ab Version 3.23.41 beinhaltet InnoDB den InnoDB-Monitor, der Informationen über den internen Zustand von InnoDB ausgibt. Wenn er angeschaltet ist, veranlasst der InnoDB-Monitor den MySQL-Server mysqld, etwa alle 15 Sekunden Daten an die Standardausgabe auszugeben (Hinweis: der MySQL-Client gibt nichts aus). Diese Daten sind nützlich, um die Performance zu tunen. Unter Windows müssen Sie mysqld-max von einer DOS-Kommandozeile aus mit --standalone --console starten, um die Ausgabe auf das DOS-Fenster umzuleiten.

Es gibt einen separaten innodb_lock_monitor, der dieselben Informationen ausgibt wie innodb_monitor, aber zusätzlich Informationen über Sperren, die durch jede Transaktion gesetzt werden.

Die ausgegebene Information enthält Daten über:

  • Sperren, die auf eine Transaktion warten,

  • Semaphore, die auf Threads warten,

  • anhängige Datei-Ein- und -Ausgabeanforderungen,

  • Puffer-Pool-Statistiken und

  • Bereinigungs- (purge) und Einfüge-Puffer-Vermengungs- (merge) Aktivität des Haupt-Threads von InnoDB.

Sie können den InnoDB-Monitor mit folgendem SQL-Befehl starten:

CREATE TABLE innodb_monitor(a int) type = innodb;

Und ihn mit folgendem Befehl anhalten:

DROP TABLE innodb_monitor;

Die CREATE TABLE-Syntax ist nur eine Möglichkeit, einen Befehl durch den MySQL-SQL-Parser an die InnoDB-Engine durchzureichen. Wenn Sie die Datenbank herunter fahren, während der Monitor läuft, und Sie den Monitor erneut starten wollen, müssen Sie die Tabelle löschen, bevor Sie ein erneutes CREATE TABLE absetzen können, um den Monitor zu starten. Diese Syntax wird sich in zukünftigen Releases möglicherweise ändern.

Beispiel für die Ausgabe des InnoDB-Monitors:

================================
010809 18:45:06 INNODB MONITOR OUTPUT
================================
--------------------------
LOCKS HELD BY transactions
--------------------------
LOCK INFO:
Number of locks in the record hash table 1294
LOCKS FOR TRANSACTION ID 0 579342744
TABLE LOCK table test/tabelle trx id 0 582333343 lock_mode IX

RECORD LOCKS space id 0 page no 12758 n bits 104 table test/tabelle index
PRIMARY trx id 0 582333343 lock_mode X
Record lock, heap no 2 PHYSICAL RECORD: n_fields 74; 1-byte offs FALSE;
info bits 0
 0: len 4; hex 0001a801; asc ;; 1: len 6; hex 000022b5b39f; asc ";; 2: len 7;
hex 000002001e03ec; asc ;; 3: len 4; hex 00000001;
...
-----------------------------------------------
CURRENT SEMAPHORES RESERVED AND SEMAPHORE WAITS
-----------------------------------------------
SYNC INFO:
Sorry, cannot give mutex list info in non-debug version!
Sorry, cannot give rw-lock list info in non-debug version!
-----------------------------------------------------
SYNC ARRAY INFO: reservation count 6041054, signal count 2913432
4a239430 waited for by thread 49627477 op. S-LOCK file NOT KNOWN line 0 
Mut ex 0 sp 5530989 r 62038708 sys 2155035; rws 0 8257574 8025336; rwx 0 1121090 1848344
-----------------------------------------------------
CURRENT PENDING FILE I/O'S
--------------------------
Pending normal aio reads:
Reserved slot, messages 40157658 4a4a40b8
Reserved slot, messages 40157658 4a477e28
...
Reserved slot, messages 40157658 4a4424a8
Reserved slot, messages 40157658 4a39ea38
Total of 36 reserved aio slots
Pending aio writes:
Total of 0 reserved aio slots
Pending insert buffer aio reads:
Total of 0 reserved aio slots
Pending log writes or reads:
Reserved slot, messages 40158c98 40157f98
Total of 1 reserved aio slots
Pending synchronous reads or writes:
Total of 0 reserved aio slots
-----------
BUFFER POOL
-----------
LRU list length 8034 
Free list length 0 
Flush list length 999 
Buffer pool size in pages 8192
Pending reads 39 
Pending writes: LRU 0, flush list 0, single page 0
Pages read 31383918, created 51310, written 2985115
----------------------------
END OF INNODB MONITOR OUTPUT
============================
010809 18:45:22 InnoDB starts purge
010809 18:45:22 InnoDB purged 0 pages

Einige Anmerkungen zur Ausgabe:

  • Wenn der Abschnitt LOCKS HELD BY transactions warten auf Sperren berichtet, kann es sein, dass Ihre Applikation Sperr-Konflikte hat. Die Ausgabe kann auch helfen, Gründe für Transaktions-Blockierungen aufzuspüren.

  • Der Abschnitt SYNC INFO berichtet reservierte Semaphore, wenn Sie InnoDB mit UNIV_SYNC_DEBUG kompilieren, definiert in univ.i.

  • Der Abschnitt SYNC ARRAY INFO berichtet Threads, die auf ein Semaphor warten, und Statistiken, wie viele Male Threads ein Spin oder ein Warten auf einem Mutex oder einem Lese-/Schreibe-Sperr-Semaphor benötigten. Eine große Anzahl auf Semaphore wartender Threads kann ein Ergebnis von Festplatten-Ein- und -Ausgaben oder Konfliktproblemen innerhalb von InnoDB sein. Konflikte können durch starke Parallelen von Anfragen oder durch Probleme des Betriebssystems beim Thread Scheduling hervorgerufen werden.

  • Der Abschnitt CURRENT PENDING FILE I/O'S listet anhängige Datei-Ein- und -Ausgabeanforderungen auf. Eine große Anzahl davon zeigt an, dass die Auslastung Festplatten-Ein- und -Ausgabe-gebunden ist.

  • Der Abschnitt BUFFER POOL gibt statistische Informationen über gelesene und geschriebene Seiten. Aus diesen Zahlen können Sie errechnen, wie viele Daten-Datei-Ein- und Ausgaben Ihre Anfragen aktuell durchführen.

8.5.10. Implementation des Multiversionings

Weil InnoDB eine multiversionierte Datenbank ist, muss es Informationen über alte Versionen von Zeilen im Tabellenplatz (Tablespace) aufbewahren. Diese Informationen werden in einer Datenstruktur gespeichert, die wir in Anlehnung an eine analoge Struktur in Oracle Rollback-Segment nennen.

InnoDB fügt jeder Zeile, die in der Datenbank gespeichert wird, intern zwei Felder hinzu. Ein 6 Byte großes Feld enthält den Transaktions-Identifikator der letzten Transaktion, die die Zeile eingefügt oder aktualisiert hat. Ein Löschen wir intern als eine Aktualisierung behandelt, wobei ein spezielles Bit in die Zeile eingefügt wird, um sie als gelöscht zu markieren. Jede Zeile enthält ausserdem ein 7 Byte großes Feld, das Roll-Zeiger genannt wird. Der Roll-Zeiger zeigt auf einen Rückgängig-Log-Datensatz, der in das Rollback-Segment geschrieben wird. Wenn die Zeile aktualisiert wurde, enthält der Rückgängig-Log-Datensatz die Informationen, die notwendig sind, um den Inhalt der Zeile wieder herzustellen, bevor sie aktualisiert wurde.

InnoDB benutzt die Informationen im Rollback-Segment, um die Rückgängig-Operationen durchzuführen, die bei einem Transaktions-Rollback notwendig sind. Diese Informationen benutzt es auch dafür, um frühere Informationen einer Zeile beim Konsistenten Lesen aufzubauen.

Rückgängig-Logs im Rollback-Segment lassen sich in Logs für Einfügen und für Aktualisieren unterteilen. Einfüge-Rückgängig-Logs werden nur für Transaktions-Rollbacks benötigt und können verworfen werden, sobald die Transaktion abgeschickt ist (commit). Aktualisierungs-Rückgängig-Logs werden auch für Konsistentes Lesens benutzt und können daher erst verworfen werden, wenn keine Transaktion mehr vorhanden ist, für die InnoDB einen Schnappschuss zugewiesen hat, dessen Informationen beim Konsistenten Lesen benötigt werden könnten, um daraus eine frühere Version der Datenbank-Zeile aufzubauen.

Sie müssen daran denken, Ihre Transaktionen regelmäßig abzuschicken (commit), auch die Transaktionen, die nur Konsistentes Lesens ausführen. Ansonsten kann InnoDB Daten aus dem Aktualisierungs-Rückgängig-Log nicht verwerfen und das Rollback-Segment könnte zu Groß werden und Ihren Tabellenplatz (Tablespace) komplett füllen.

Die physikalische Größe eines Rückgängig-Log-Datensatzes im Rollback-Segment ist typischerweise kleiner als die entsprechende eingefügte oder aktualisierte Zeile. Sie können diese Informationen benutzen, um den Platzbedarf für Ihr Rollback-Segment zu berechnen.

In diesem multiversionierten Schema wird eine Zeile nicht unmittelbar physikalisch aus der Datenbank entfernt, wenn Sie sie mit einem SQL-Statement löschen. Erst wenn InnoDB den Datensatz des Aktualisierungs-Rückgängig-Logs löschen kann, der für das Löschen geschrieben wurde, kann es die entsprechende Zeile und ihre Index-Datensätze auch physikalisch aus der Datenbank entfernen. Diese Entfernungsoperation wird Purge genannt und ist recht schnell, wobei sie überschlägig dieselbe Zeit benötigt wie das SQL-Statement, das das Löschen ausführte.

8.5.11. Tabellen- und Index-Strukturen

MySQL speichert seine Daten-Wörterbuch-Informationen über Tabellen in .frm-Dateien in den Datenbank-Verzeichnissen. Jedoch hat auch jede Tabelle vom Typ InnoDB ihren eigenen Eintrag, in InnoDB-internen Daten-Wörterbüchern innerhalb des Tabellenplatzes (Tablespace). Wenn MySQL eine Tabelle oder Datenbank löscht, muss er sowohl eine oder mehrere .frm-Datei(en) als auch die entsprechenden Einträge im InnoDB-Daten-Wörterbuch löschen. Das ist der Grund, warum Sie InnoDB-Tabellen nicht einfach zwischen Datenbanken verschieben können, indem Sie die .frm-Dateien verschieben und warum DROP DATABASE bei InnoDB-Tabellen in MySQL-Versionen bis 3.23.43 nicht funktionierte.

Jede InnoDB-Tabelle hat einen speziellen Index, der Cluster-Index genannt wird, in dem die Daten der Zeilen gespeichert sind. Wenn Sie auf Ihre Tabelle einen PRIMARY KEY definieren, ist der Index des Primärschlüssels der Cluster-Index.

Wenn Sie für Ihre Tabelle keinen Primärschlüssel definieren, erzeugt InnoDB intern einen Cluster-Index, bei dem die Zeilen nach der Zeilen-Kennung (ID) geordnet sind, die InnoDB Zeilen in einer solchen Tabelle zuweist. Die Zeilen-Kennung ist ein 6 Byte großes Feld, das monoton erhöht wird, wenn neue Zeilen eingefügt werden. Daher liegen nach der Zeilen-Kennung geordnete Zeile physikalisch in der Einfüge-Reihenfolge vor.

Der Zugriff auf eine Zeile über den Cluster-Index ist schnell, weil die Zeilendaten auf derselben Seite sind, auf die die Index-Suche führt. In vielen Datenbanken werden die Daten traditionell auf einer anderen Seite als derjenigen, wo sich der Index-Datensatz befindet, gespeichert. Wenn die Tabelle Groß ist, spart die Cluster-Index-Architektur im Vergleich zur traditionellen Lösung auf Festplatten-Ein- und -Ausgaben.

In InnoDB enthalten die Datensätze in Nicht-Cluster-Indexen (die wir auch sekundäre Indexe nennen) den Primärschlüsselwert für die Zeile. InnoDB benutzt diesen Primärschlüsselwert, um vom Cluster-Index aus nach der Zeile zu suchen. Beachten Sie, dass die sekundären Indexe mehr Platz benötigen, wenn der Primärschlüssel lang ist.

8.5.11.1. Physikalische Struktur eines Indexes

Alle Indexe in InnoDB sind B-Bäume, in denen die Index-Datensätze in den Blätter-Seiten des Baums gespeichert sind. Die vorgabemäßige Größe einer Index-Seite ist 16 KB. Wenn neue Datensätze eingefügt werden, versucht InnoDB, 1/16 der Seite für zukünftige Einfügungen und Aktualisierungen des Index-Datensatzes freizuhalten.

Wenn Index-Datensätze in sequentieller (aufsteigender oder absteigender) Reihenfolge eingefügt werden, sind die resultierenden Index-Seiten ungefähr zu 15/16 gefüllt. Wenn der Füllfaktor einer Index-Seite unter 1/12 fällt, versucht InnoDB, den Index-Baum zusammenzuziehen, um die Seite freizugeben.

8.5.11.2. Einfügepufferung

Häufig wird der Primärschlüssel in Datenbank-Applikationen als eindeutiger Identifizierer benutzt und neue Zeilen in aufsteigender Reihenfolge des Primärschlüssels eingefügt. Daher erfordern Einfügungen in den Cluster-Index keine wahlfreien (random) Lesezugriffe auf die Platte.

Sekundäre Indexe auf der anderen Seite sind üblicherweise nicht eindeutig und Einfügungen in sekundäre Indexe erfolgen in einer relativ wahlfreien Reihenfolge. Wenn InnoDB keinen speziellen Mechanismus hierfür benutzen würde, würden diese viele wahlfreie Festplatten-Ein- und -Ausgaben verursachen.

Wenn ein Index-Datensatz in einen nicht eindeutigen sekundären Index eingefügt werden soll, prüft InnoDB, ob die sekundäre Index-Seite bereits im Puffer-Pool ist. Wenn das der Fall ist, führt InnoDB das Einfügen direkt in die Index-Seite durch. Wenn die Index-Seite aber nicht im Puffer-Pool gefunden wird, fügt InnoDB den Datensatz in eine spezielle Einfüge-Puffer-Struktur ein. Der Einfüge-Puffer wird so klein gehalten, dass er komplett in den Puffer-Pool passt, so dass Einfügungen sehr schnell durchgeführt werden können.

Der Einfüge-Puffer wird periodisch mit den sekundären Index-Bäumen in der Datenbank vermengt. Oft können mehrere Einfügeoperationen auf derselben Seite im Index-Baum zusammengefasst werden, so dass Festplatten-Ein- und -Ausgaben eingespart werden. Messungen ergaben, dass der Einfüge-Puffer Einfügungen in eine Tabelle bis zu 15 mal schneller machen kann.

8.5.11.3. Anpassungsfähige Hash-Indexe

Wenn eine Datenbank fast komplette in den Hauptspeicher passt, können Anfragen am schnellsten unter Verwendung von Hash-Indexen ausgeführt werden. InnoDB hat einen automatischen Mechanismus, der Index-Suchen beobachtet, die auf den Indexen durchgeführt werden, die für eine Tabelle definiert wurden. Wenn InnoDB bemerkt, dass Anfragen vom Aufbauen eines Hash-Indexes profitieren könnten, wird ein solcher Index automatisch aufgebaut.

Beachten Sie aber, dass der Hash-Index immer auf der Grundlage eines bestehenden B-Baum-Indexes auf die Tabelle aufgebaut wird. InnoDB kann einen Hash-Index auf einem Präfix beliebiger Länge des Schlüssels aufbauen, der für den B-Baum definiert wurde, abhängig vom Suchmuster, das InnoDB auf dem Index-Baum beobachtet. Ein Hash-Index kann partiell sein: Es ist nicht erforderlich, dass der gesamte Index-Baum im Puffer-Pool zwischengespeichert ist. InnoDB baut Hash-Indexe bei Bedarf automatisch für die Index-Seiten auf, auf die oft zugegriffen wird.

In gewisser Hinsicht kommt InnoDB durch den anpassungsfähigen Hash-Index-Mechanismus (wobei sich InnoDB üppig verfügbarem Hauptspeicher anpasst) der Architektur von Hauptspeicher-Datenbanken nahe.

8.5.11.4. Physikalische Datensatzstruktur

  • Jeder Index-Datensatz in InnoDB enthält einen Header von 6 Bytes. Der Header wird benutzt, um nachfolgende Datensätze zu verknüpfen, sowie beim Sperren auf Zeilenebene.

  • Datensätze im Cluster-Index enthalten Felder für alle benutzerdefinierten Spalten. Zusätzlich gibt es ein 6 Byte großes Feld für die Transaktions-Kennung und ein 7 Byte großes Feld für den Roll-Zeiger.

  • Wenn der Benutzer keinen Primärschlüssel für eine Tabelle definiert hat, enthält jeder Cluster-Index-Datensatz zusätzlich ein 6 Byte großes Zeilenkennungsfeld.

  • Jeder sekundäre Index-Datensatz enthält auch alle Felder, die für den Cluster-Index-Schlüssel definiert wurden.

  • Ein Datensatz enthält auch einen Zeiger zu jedem Feld des Datensatzes. Wenn die Gesamtlänge des Feldes in einem Datensatz kleiner als 128 Bytes ist, ist der Zeiger 1 Byte lang, ansonsten 2 Bytes.

8.5.11.5. Wie eine Auto-Increment-Spalte in InnoDB funktioniert

Wenn der Benutzer nach einem Datenbankstart zuerst einen Datensatz in eine Tabelle T einfügt, in der eine Auto-Increment-Spalte definiert wurde, und er keinen expliziten Wert für die Spalte angibt, führt InnoDB SELECT MAX(auto-inc-column) FROM T aus und weist den um 1 hochgezählten Wert der Spalte und dem Auto-Increment-Zähler der Tabelle zu. Wir sagen dazu, dass der Auto-Increment-Zähler für Tabelle T initialisiert wurde.

InnoDB führt dieselbe Prozedur der Initialisierung des Auto-Increment-Zählers für eine frisch erzeugte Tabelle durch.

Wenn Sie für die Auto-Increment-Spalte einen Wert von 0 angeben, beachten Sie, dass InnoDB die Zeile so behandelt, als hätten Sie den Wert nicht angegeben.

Wenn nach der Initialisierung des Auto-Increment-Zählers der Benutzer eine Zeile eingibt, in der er explizit den Spaltenwert angibt, und dieser größer als der aktuelle Zählerwert ist, wird der Zähler auf den angegebenen Spaltenwert gesetzt. Wenn der Benutzer nicht explizit einen Wert angibt, zählt InnoDB den Zähler um 1 hoch und weist der Spalte diesen neuen Wert zu.

Der Auto-Increment-Mechanismus umgeht beim Zuweisen von Werten vom Zähler Sperren und Transaktionshandhabung. Daher können Lücken in der Nummernfolge entstehen, wenn Sie Transaktionen zurückrollen (Rollback), die Nummern vom Zähler erhalten haben.

Das Verhalten von Auto-Increment ist für die Fälle undefiniert, in denen ein Benutzer der Spalte einen negativen Wert gibt oder wenn der Wert größer als die größte Ganzzahl wird, die im festgelegten Ganzzahl-Typ gespeichert werden kann.

8.5.12. Verwaltung von Datei-Speicherplatz und Festplatten-Eingaben / -Ausgaben

8.5.12.1. Festplatten-Ein- und -Ausgaben

Bei Festplatten-Ein- und -Ausgaben benutzt InnoDB asynchrone Ein- und Ausgaben. Unter Windows NT benutzt es die nativen Ein- und Ausgaben, die vom Betriebssystem zur Verfügung gestellt werden. Unter Unix benutzt InnoDB simulierte asynchrone Ein- und Ausgaben, die in InnoDB eingebaut sind: InnoDB erzeugt eine Reihe von Ein-/Ausgabe-Threads, die sich um Ein- und Ausgabeoperationen kümmern, zum Beispiel Vorwärts-Lesen (Read-Ahead). Zukünftig werden wir auch für Windows NT simulierte Ein-/Ausgaben unterstützen sowie für die Unix-Versionen, die so etwas besitzen, native Ein-/Ausgaben.

Unter Windows NT benutzt InnoDB ungepufferte Ein- und Ausgaben. Das heißt, dass die Festplatten-Seiten, die InnoDB liest oder schreibt, nicht im Datei-Cache des Betriebssystems gepuffert werden. Das spart einiges an Arbeitsspeicher-Bandbreite.

Ab Version 3.23.41 benutzt InnoDB eine neuartige Datei-Flush-Technik, die Doublewrite heißt. Sie erhöht die Sicherheit bei Reparaturen nach Absturz, wenn ein Betriebssystemabsturz oder ein Stromausfall aufgetreten sind, und verbessert auf den meisten Unix-Versionen die Performance, indem die Notwendigkeit von Fsync-Operationen verringert wird.

Doublewrite bedeutet, dass InnoDB zuerst in einen zusammenhängenden Tabellenplatz (Tablespace) namens Doublewrite-Puffer schreibt, bevor Seiten in eine Daten-Datei geschrieben werden. Erst nachdem das Schreiben und Zurückschreiben (Flush) in den Doublewrite-Puffer fertig sind, schreibt InnoDB die Seiten an ihre korrekten Positionen in der Daten-Datei. Wenn das Betriebssystem mitten in einem Seiten-Schreiben abstürzt, findet InnoDB bei der Wiederherstellung eine gute Kopie der Seite im Doublewrite-Puffer.

Ab Version 3.23.41 können Sie auch eine Raw-Disk-Partition als Daten-Datei benutzen, obwohl das bisher noch nicht getestet wurde. Wenn Sie eine neue Daten-Datei erzeugen, müssen Sie das Schlüsselwort newraw unmittelbar nach der Daten-Datei-Größe in innodb_data_file_path angeben. Die Partition muss größer oder gleich der Größe sein, die Sie angeben. Beachten Sie, dass in InnoDB 1 MB 1024 x 1024 Bytes ist, während 1 MB in Festplatten-Spezifikationen üblicherweise 1.000.000 Bytes bedeutet.

innodb_data_file_path=hdd1:5Gnewraw;hdd2:2Gnewraw

Wenn Sie die Datenbank wieder starten, müssen -sue das Schlüsselwort in raw ändern. Ansonsten schreibt InnoDB über Ihre Partition!

innodb_data_file_path=hdd1:5Graw;hdd2:2Graw

Wenn Sie Raw-Disk benutzen, können Sie unter einigen Unixen ungepufferte Ein- und Ausgaben ausführen.

Es gibt zwei Vorwärts-Lesen-(Read-Ahead-)Heuristiken in InnoDB: sequentielles Vorwärts-Lesen und wahlfreies (random) Vorwärts-Lesen. Beim sequentiellen Vorwärts-Lesen bemerkt InnoDB, dass das Zugriffsschema auf ein Segment im Tabellenplatz (Tablespace) sequentiell ist. InnoDB schickt dann vorab einen Stapel von Lesevorgängen von Datenbankseiten an das Ein-/Ausgabesystem. Beim wahlfreien Vorwärts-Lesen bemerkt InnoDB, dass ein bestimmter Bereich im Tabellenplatz (Tablespace) im Zustand des vollständig Eingelesenwerdens in den Puffer-Pool zu sein scheint. Dann schickt InnoDB die verbleibenden Lesevorgänge an das Ein-/Ausgabesystem.

8.5.12.2. Speicherplatzverwaltung

Die Daten-Dateien, die Sie in der Konfigurationsdatei definieren, formen den Tabellenplatz (Tablespace) von InnoDB. Die Dateien werden einfach verkettet, um den Tabellenplatz (Tablespace) zu formen, es wird kein Striping benutzt. Momentan können Sie nicht direkt angeben, wo der Platz für Ihre Tabellen zugewiesen werden soll, ausser wenn Sie folgende Tatsache benutzen: InnoDB weist Speicherplatz von einem neu erzeugten Tabellenplatz (Tablespace) vom niedrigen Ende ausgehend zu.

Der Tabellenplatz (Tablespace) besteht aus Datenbankseiten, deren vorgabemäßige Größe 16 KB beträgt. Diese Seiten werden bis zu einer Ausdehnung von 64 aufeinander folgenden Seiten gruppiert. Die 'Dateien' innerhalb eines Tabellenplatzes (Tablespace) werden in InnoDB Segmente genannt. Der Name des Rollback-Segments ist in gewisser Hinsicht irreführend, weil dieses tatsächlich viele Segmente im Tabellenplatz enthält.

Für jeden Index in InnoDB werden zwei Segmente zugewiesen: eins für die Nicht-Blätter-Knoten (Non-Leaf-Nodes) des B-Baum, das andere für die Blätter-Knoten. Die Idee dahinter ist, für die Blätter-Knoten, die die Daten enthalten, bessere Sequentialität zu erzielen.

Wenn ein Segment innerhalb des Tabellenplatzes anwächst, weist ihm InnoDB die ersten 32 Seiten individuell zu. Danach fängt InnoDB an, dem Segment ganze Ausdehnungen zuzuweisen. InnoDB kann einem großen Segment bis zu vier Ausdehnungen auf einmal hinzufügen, um gute Sequentialität für die Daten sicherzustellen.

Einige Seiten im Tabellenplatz enthalten Bitmaps anderer Seiten. Daher können einige Ausdehnungen in einem InnoDB-Tabellenplatz (Tablespace) nicht Segmenten als Ganzes zugewiesen werden, sondern nur als individuelle Seiten.

Wenn Sie eine Anfrage SHOW TABLE STATUS FROM ... LIKE ... ausführen, um den verfügbaren freien Platz im Tabellenplatz festzustellen, berichtet InnoDB den Platz, der in völlig freien Ausdehnungen im Tabellenplatz sicher benutzt werden kann. InnoDB reserviert immer einige Ausdehnungen für Säuberungs- und interne Zwecke. Diese Ausdehnungen werden nicht in den freien Platz einbezogen.

Wenn Sie Daten aus einer Tabelle löschen, zieht InnoDB die entsprechenden B-Baum-Indexe zusammen. Es hängt vom Schema der Löschvorgänge ab, ob das individuelle Seiten oder Ausdehnungen im Tabellenplatz freigibt, so dass der freigegebene Platz anderen Benutzern zur Verfügung steht. Wenn eine Tabelle gelöscht wird oder alle Zeilen aus ihr gelöscht werden, gibt das garantiert Platz frei für andere Benutzer, aber denken Sie daran, dass gelöschte Zeile physikalisch nur durch eine Purge-Operation entfernt werden können, nachdem Sie nicht mehr für ein Transaktions-Rollback oder für Konsistentes Lesen benötigt werden.

8.5.12.3. Eine Tabelle defragmentieren

Wenn es wahlfreie (random) Einfüge- oder Löschvorgänge in die Indexe einer Tabelle gibt, können die Indexe fragmentiert werden. Unter Fragmentierung verstehen wird, dass die physikalische Reihenfolge der Index-Seiten auf der Platte der alphabetischen Reihenfolge der Datensätze auf den Seiten nicht nahe kommt oder dass es viele unbenutzte Seiten in den 64-Seiten-Blöcken gibt, die dem Index zugewiesen wurden.

Index-Scans können beschleunigt werden, wenn Sie von Zeit zu Zeit mysqldump benutzen, um die Tabelle in eine Textdatei zu dumpen, dann die Tabelle zu löschen und sie aus dem Dump neu aufzubauen. Eine weitere Möglichkeit zur Defragmentierung besteht darin, den Tabellentyp in MyISAM zu ändern (ALTER) und danach wieder in InnoDB zurück. Beachten Sie, dass die MyISAM-Tabelle auf Ihrem Betriebssystem in eine einzige Datei passen muss.

Wenn die Einfügungen in einen Index immer aufsteigend sind und Datensätze nur vom Ende gelöscht werden, garantiert der Speicherplatzverwaltungs-Algorithmus von InnoDB, dass keine Fragmentierung im Index auftritt.

8.5.13. Fehlerbehandlung

Die Fehlerbehandlung in InnoDB ist nicht immer so, wie es die ANSI-SQL-Standards festlegen. Nach ANSI-Standard sollte jeder Fehler während eines SQL-Statements ein Rollback des Statements verursachen. InnoDB rollt manchmal nur Teile des Statements oder auch die gesamte Transaktion zurück. Folgende Liste gibt die Fehlerbehandlung von InnoDB an:

  • Wenn es keinen Speicherplatz mehr im Tabellenplatz (Tablespace) gibt, bekommen Sie den MySQL-Fehler 'Table is full' und InnoDB rollt das SQL-Statement zurück.

  • Eine Transaktions-Blockierung oder eine Zeitüberschreitung beim Warten auf eine Sperre führen dazu, dass InnoDB die gesamte Transaktion zurückrollt.

  • Ein Fehler wegen doppelter Schlüsseleinträge rollt das Einfügen dieser Zeile zurück, selbst in einem Statement wie INSERT INTO ... SELECT .... Das wird sich voraussichtlich ändern, so dass das SQL-Statement zurückgerollt wird, wenn Sie die IGNORE-Option in Ihrem Statement nicht angegeben haben.

  • Ein Fehler 'row too long' rollt das SQL-Statement zurück.

  • Andere Fehler werden zumeist durch die MySQL-Code-Ebene entdeckt und rollen das entsprechende SQL-Statement zurück.

8.5.14. Beschränkungen von InnoDB-Tabellen

  • ACHTUNG: Konvertieren Sie KEINE MySQL-Systemtabellen von MyISAM in InnoDB-Tabellen! Das wird nicht unterstützt. Wenn Sie es dennoch tun, startet MySQL nicht mehr, bis Sie die alten Systemtabellen aus einer Datensicherung wiederhergestellt haben oder sie mit dem mysql_install_db-Skript neu erzeugen.

  • SHOW TABLE STATUS gibt keine genauen Statistiken über InnoDB-Tabellen, ausser über die physikalische Größe, die durch die Tabelle reserviert wird. Der Zeilenzähler ist nur eine grobe Schätzung, die bei der SQL-Optimierung benutzt wird.

  • Wenn Sie versuchen, einen eindeutigen Index auf ein Präfix einer Spalte zu erzeugen, erhalten Sie einen Fehler:

    CREATE TABLE T (A CHAR(20), B INT, UNIQUE (A(5))) TYPE = InnoDB;
    

    Wenn Sie einen nicht eindeutigen Index auf ein Spaltenpräfix erzeugen, erzeugt InnoDB einen Index über die gesamte Spalte.

  • INSERT DELAYED wird für InnoDB-Tabellen nicht unterstützt.

  • Die MySQL-LOCK TABLES-Operation weiß nichts von InnoDB-Sperren auf Zeilenebene, die in bereits fertigen SQL-Statements gesetzt sind. Das bedeutet, dass Sie eine Tabellensperre auf eine Tabelle selbst dann erhalten können, wenn es noch Transaktionen anderer Benutzer gibt, die Sperren auf Zeilenebene auf dieselbe Tabelle haben. Daher kann es sein, dass Ihre Operationen auf die Tabelle warten müssen, wenn sie mit diesen Sperren anderer Benutzer kollidieren. Auch eine Blockierung ist möglich. Dennoch gefährdet das nicht die Transaktionsintegrität, weil sich die Sperren auf Zeilenebene, die InnoDB setzt, um die Integrität kümmern. Zusätzlich hindert eine Tabellensperren andere Transaktionen daran, weitere Sperren auf Zeilenebene (in einem konfliktbehafteten Sperrmodus) auf die Tabelle zu erlangen.

  • Sie können keinen Schlüssel auf eine BLOB- oder TEXT-Spalte setzen.

  • Eine Tabelle kann nicht mehr als 1.000 Spalten enthalten.

  • DELETE FROM TABLE erzeugt die Tabelle nicht neu, sondern löscht statt dessen alle Zeilen, eine nach der anderen, was nicht sehr schnell ist. In zukünftigen MySQL-Versionen können Sie TRUNCATE benutzen, was schnell ist.

  • Die vorgabemäßige Datenbank-Seitengröße in InnoDB beträgt 16 KB. Indem Sie den Code neu kompilieren, können Sie sie auf Werte zwischen 8 KB und 64 KB setzen. Die maximale Zeilenlänge beträgt etwas weniger als die Hälfte der Datenbank-Seite in den InnoDB-Versionen kleiner oder gleich 3.23.40. Ab Quelldistribution 3.23.41 dürfen BLOB- und TEXT-Spalten bis zu 4 GB Groß sein, die gesamte Zeilenlänge kann auch < 4 GB betragen. InnoDB speichert Felder, deren Größe kleiner oder gleich 128 Bytes beträgt, nicht auf separaten Seiten. Nachdem InnoDB die Zeile geändert hat, indem lange Felder auf separaten Seiten gespeichert werden, muss die restliche Zeilenlänge weniger als die Hälfte einer Datenbank-Seite betragen. Die maximale Schlüssellänge beträgt 7.000 Bytes.

  • Auf einigen Betriebssystemen müssen Daten-Dateien kleiner als 2 GB sein. Die Gesamtgröße der Log-Dateien muss auf 32-Bit-Computern kleiner als 4 GB sein.

  • Die maximale Größe des Tabellenplatzes (Tablespace) beträgt 4 Milliarden Datenbank-Seiten. Das ist auch die maximale Größe für eine Tabelle. Die minimale Größe des Tabellenplatzes (Tablespace) beträgt 10 MB.

8.5.15. InnoDB-Kontaktinformationen

Kontaktinformationen von Innobase Oy, Hersteller der InnoDB-Engine: Website: http://www.innodb.com/. E-Mail:

Telefon: 358-9-6969 3250 (Büro) 358-40-5617367 (mobil)
Innobase Oy Inc.
World Trade Center Helsinki
Aleksanterinkatu 17
P.O.Box 800
00101 Helsinki
Finnland

8.6. BDB- oder Berkeley_db-Tabellen

8.6.1. Überblick über BDB-Tabellen

Unterstützung für BDB-Tabellen ist in der MySQL-Quelldistribution seit Version 3.23.34 enthalten und in der MySQL-Max-Binärdistribution aktiviert.

BerkeleyDB, erhältlich unter http://www.sleepycat.com/, stattet MySQL mit einem transaktionalen Tabellen-Handler aus. Wenn Sie BerkeleyDB-Tabellen benutzen, haben Ihre Tabellen eine höhere Chance, Abstürze zu überleben. Zusätzlich stehen COMMIT und ROLLBACK für Transaktionen zur Verfügung. Die MySQL-Quelldistribution enthält eine BDB-Distribution, die eine Reihe kleiner Patches hat, damit sie glatter mit MySQL zusammen arbeitet. Sie können keine nicht gepatchte BDB-Version für MySQL verwenden.

Wir bei MySQL AB arbeiten in enger Kooperation mit Sleepycat, um die hohe Qualität der MySQL-/BDB-Schnittstelle zu halten.

Was den Support für BDB-Tabellen angeht, sehen wir uns in der Pflicht, unseren Benutzern zu helfen, Probleme zu lokalisieren und Ihnen zu helfen, einen reproduzierbaren Testfall für jegliche Probleme mit BDB-Tabellen zu erstellen. Solche ein Fall wird an Sleepycat weiter geleitet, die sich dann an uns wenden, um uns zu helfen, das Problem zu finden und zu beheben. Weil das also in zwei Schritten abläuft, kann es bei jeglichen Problemen mit BDB-Tabellen etwas länger dauern, diese zu lösen, als das bei anderen Tabellen-Handlern der Fall ist. Weil jedoch der BerkeleyDB-Code selbst auch von vielen sonstigen Applikationen benutzt wird, sind hierbei keine großen Probleme zu erwarten. See Abschnitt 2.4.1, „Support den MySQL AB anbietet“.

8.6.2. BDB installieren

Wenn Sie eine Binärdistribution von MySQL herunter geladen haben, die Unterstützung für BerkeleyDB enthält, folgen Sie einfach den Anweisungen zur Installation einer Binärversion von MySQL. See Abschnitt 3.2.6, „MySQL-Binärdistributionen, die von MySQL AB kompiliert wurden“. See Abschnitt 5.7.5, „mysqld-max, ein erweiterter mysqld-Server“.

Um MySQL mit BerkeleyDB-Unterstützung zu kompilieren, laden Sie MySQL-Version 3.23.34 oder neuer herunter und konfigurieren Sie MySQL mit der --with-berkeley-db-Option.

See Abschnitt 3.3, „Installation der Quelldistribution“.

cd /pfad/zur/quelle/von/mysql-3.23.34
./configure --with-berkeley-db

Bitte sehen Sie wegen aktuellerer Informationen im Handbuch nach, das mit der BDB-Distribution mitgeliefert wird.

Obwohl BerkeleyDB selbst sehr gut getestet und zuverlässig ist, wird die MySQL-Schnittstelle noch als Beta-Qualität erachtet. Wir verbessern diese aktiv und optimieren sie, um sie sehr bald stabil zu bekommen.

8.6.3. BDB-Startoptionen

Wenn Sie mit AUTOCOMMIT=0 fahren, werden Ihre Änderungen in BDB-Tabellen erst aktualisiert, wenn Sie COMMIT ausführen. Statt dessen können Sie ROLLBACK ausführen, um Ihre Änderungen zu verwerfen. See Abschnitt 7.7.1, „BEGIN/COMMIT/ROLLBACK-Syntax“.

Wenn Sie mit AUTOCOMMIT=1 fahren (der Vorgabe), werden Ihre Änderungen sofort abgeschickt. Sie können eine ausgedehnte Transaktion mit dem SQL-Befehl BEGIN WORK starten. Danach werden Ihre Änderungen solange nicht abgeschickt, bis Sie COMMIT ausführen (oder sich für ROLLBACK entscheiden, um Ihre Änderungen zu verwerfen).

Folgende Optionen für mysqld können benutzt werden, um das Verhalten von BDB-Tabellen zu ändern:

OptionBeschreibung
--bdb-home=directoryBase Verzeichnis für BDB-Tabellen. Das sollte dasselbe Verzeichnis sein, das Sie für --datadir benutzen.
--bdb-lock-detect=#Berkeley-Sperr-Erkennung. # steht für DEFAULT, OLDEST, RANDOM oder YOUNGEST.
--bdb-logdir=VerzeichnisBerkeleyDB-Log-Datei-Verzeichnis.
--bdb-no-syncFlush-Logs nicht synchronisieren.
--bdb-no-recoverBerkeleyDB nicht im Wiederherstellungsmodus starten.
--bdb-shared-dataBerkeleyDB im Multi-Prozess-Modus starten (DB_PRIVATE bei der Initialisierung von BerkeleyDB nicht verwenden).
--bdb-tmpdir=verzeichnisName der temporären Datei von BerkeleyDB.
--skip-bdbBerkeleyDB nicht benutzen.
-O bdb_max_lock=1000Setzt die höchste Anzahl möglicher Sperren. See Abschnitt 5.5.5.4, „SHOW VARIABLES.

Wenn Sie --skip-bdb benutzen, initialisiert MySQL nicht die BerkeleyDB-Bibliothek und spart deshalb viel Speicher. Natürlich können Sie BDB-Tabellen nicht benutzen, wenn Sie diese Option verwenden.

Normalerweise sollten Sie mysqld ohne --bdb-no-recover starten, wenn Sie vorhaben, BDB-Tabellen zu verwenden. Das kann allerdings zu Problemen führen, wenn Sie mysqld starten und die BDB-Log-Dateien beschädigt sind. See Abschnitt 3.4.2, „Probleme mit dem Start des MySQL-Servers“.

Mit bdb_max_lock können Sie die maximale Anzahl von Sperren festlegen (vorgabemäßig 10.000), die auf einer BDB-Tabelle aktiv sein können. Sie sollten diesen Wert herauf setzen, wenn Sie Fehler vom Typ bdb: Lock table is out of available locks oder Got error 12 from ... erhalten, wenn Sie lange Transaktionen ausführen oder wenn mysqld viele Zeilen untersuchen muss, um die Anfrage zu berechnen.

Sie könnten auch binlog_cache_size und max_binlog_cache_size ändern, wenn Sie große, vielzeilige Transaktionen benutzen. See Abschnitt 7.7.1, „BEGIN/COMMIT/ROLLBACK-Syntax“.

8.6.4. Kennzeichen von BDB-Tabellen

  • Um Transaktionen zurückrollen zu können, unterhält BDB Log-Dateien. Um maximale Performance zu erzielen, sollten Sie diese auf andere Festplatten platzieren als Ihre Datenbanken, indem Sie die --bdb_log_dir-Option benutzen.

  • MySQL macht jedes Mal, wenn eine neue BDB-Log-Datei gestartet wird, einen Checkpoint und entfernt alle Log-Dateien, die nicht für aktuelle Transaktionen benötigt werden. Sie können auch jederzeit FLUSH LOGS laufen lassen, um einen Checkpoint für die BerkeleyDB-Tabellen anzulegen.

    Für die Wiederherstellung nach Abstürzen sollten Sie Datensicherungen der Tabellen plus das Binär-Log von MySQL benutzen. See Abschnitt 5.4.1, „Datenbank-Datensicherungen“.

    Achtung: Wenn Sie alte Log-Dateien löschen, die in Benutzung sind, ist BDB nicht in der Lage, Wiederherstellungen durchzuführen, und Sie könnten Daten verlieren, wenn etwas schief geht.

  • MySQL erfordert einen PRIMARY KEY in jeder BDB-Tabelle, um auf vorher gelesene Zeilen verweisen zu können. Wenn Sie keine Primärschlüssel anlegen, erzeugt MySQL einen versteckten PRIMARY KEY. Der versteckte Schlüssel hat eine Länge von 5 Bytes und wird bei jedem Einfügeversuch um 1 hochgezählt.

  • Wenn alle Spalten, auf die Sie in einer BDB-Tabelle zugreifen, Teil desselben Indexes oder Teil des Primärschlüssels sind, kann MySQL die Anfrage ausführen, ohne auf die tatsächliche Zeile zugreifen zu müssen. Bei einer MyISAM-Tabelle gilt das nur, wenn die Spalten Teil desselben Indexes sind.

  • Der PRIMARY KEY ist schneller als jeder andere Schlüssel, weil PRIMARY KEY zusammen mit den Zeilendaten gespeichert wird. Weil die anderen Schlüssel als Schlüsseldaten plus PRIMARY KEY gespeichert werden, ist es wichtig, den PRIMARY KEY so kurz wie möglich zu halten, um Plattenplatz zu sparen und bessere Geschwindigkeit zu erzielen.

  • LOCK TABLES funktioniert bei BDB-Tabellen wie bei anderen Tabellen. Wenn Sie LOCK TABLE nicht benutzen, führt MySQL einer interne mehrfache Schreibsperre auf die Tabelle aus, um sicherzustellen, dass die Tabelle korrekt gesperrt ist, wenn ein anderer Thread eine Tabellensperre ausführt.

  • Internes Sperren in BDB-Tabellen wird auf Seitenebene durchgeführt.

  • SELECT COUNT(*) FROM tabelle ist langsam, weil BDB-Tabellen keinen Zähler für die Anzahl der Zeilen in der Tabelle unterhalten.

  • Scannen ist langsamer als bei MyISAM-Tabellen, weil Daten in BDB-Tabellen in B-Bäumen und nicht in separaten Daten-Dateien gespeichert werden.

  • Die Applikation muss stets darauf vorbereitet sein, Fälle zu handhaben, bei denen jegliche Änderung einer BDB-Tabelle zu einem automatischen Rollback führen kann und jegliches Lesen fehlschlagen kann, weil ein Blockierungsfehler auftritt.

  • Schlüssel werden nicht auf vorherige Schlüssel komprimiert, wie das bei ISAM- und MyISAM-Tabellen der Fall ist. Mit anderen Worten benötigt die Schlüsselinformation etwas mehr Platz bei BDB-Tabellen im Vergleich zu MyISAM-Tabellen, die nicht PACK_KEYS=0 benutzen.

  • Oft gibt es Löcher in der BDB-Tabelle, damit Sie neue Zeilen in der Mitte des Schlüsselbaums einfügen können. Das macht BDB-Tabellen etwas größer als MyISAM-Tabellen.

  • Der Optimierer muss näherungsweise die Anzahl von Zeilen in der Tabelle kennen. MySQL löst dieses Problem, indem Einfügeoperationen gezählt werden, und unterhält diese in einem separaten Segment in jeder BDB-Tabelle. Wenn Sie nicht viele DELETE oder ROLLBACK ausführen, sollte diese Zahl ausreichend genau für den MySQL-Optimierer sein. Weil MySQL die Zahl nur beim Schließen speichert, kann sie falsch sein, wenn MySQL unerwartet stirbt. Das sollte kein schwerer Fehler sein, selbst wenn die Zahl nicht 100% korrekt ist. Man kann die Anzahl von Zeilen aktualisieren, indem man ANALYZE TABLE oder OPTIMIZE TABLE ausführt.

    See Abschnitt 5.5.2, „ANALYZE TABLE-Syntax“. See Abschnitt 5.5.1, „OPTIMIZE TABLE-Syntax“.

  • Wenn die Platte bei einer BDB-Tabelle voll wird, erhalten Sie einen Fehler (wahrscheinlich Fehler 28) und die Transaktion sollte zurückgerollt werden. Das steht im Gegensatz zu MyISAM- and ISAM-Tabellen, bei denen mysqld wartet, bis genug Plattenplatz frei ist, bevor weiter gemacht wird.

8.6.5. Was in naher Zukunft bei BDB in Ordnung gebracht werden muss

  • Viele BDB-Tabellen zur gleichen Zeit öffnen ist sehr langsam. Wenn Sie BDB-Tabellen benutzen wollen, sollten Sie einen sehr großen Tabellen-Cache haben (evtl. größer als 256) und beim mysql-Client --no-auto-rehash benutzen. Das soll partiell in Version 4.0 behoben werden.

  • SHOW TABLE STATUS gibt momentan noch nicht viele Informationen über BDB-Tabellen aus.

  • Performance optimieren.

  • Es sollten überhaupt keine Seitensperren mehr benutzt werden, wenn Tabellen gescannt werden.

8.6.6. Betriebssysteme, die von BDB unterstützt werden

Wenn Sie MySQL mit Unterstützung für BDB-Tabellen gebaut haben und folgenden Fehler in der Log-Datei sehen, wenn Sie mysqld starten:

bdb: architecture lacks fast mutexes: applications cannot be threaded
Can't init databases

Bedeutet das, dass BDB-Tabellen für Ihre Architektur nicht unterstützt werden. In diesem Fall müssen Sie MySQL erneut bauen, ohne Unterstützung für BDB-Tabellen.

HINWEIS: Folgende Liste ist nicht komplett. Sie wird aktualisiert, sobald wir mehr Informationen darüber haben.

Momentan wissen wir, dass BDB-Tabellen auf folgenden Betriebssystemen laufen:

  • Linux 2.x intel

  • Solaris sparc

  • Caldera (SCO) OpenServer

  • Caldera (SCO) UnixWare 7.0.1

Auf folgenden Betriebssystemen läuft BDB nicht:

  • Linux 2.x Alpha

  • Mac OS X

8.6.7. Fehler, die bei der Benutzung von BDB-Tabellen auftreten können

  • Wenn Sie folgenden Fehler in der hostname.err-Log-Datei beim Start von mysqld erhalten:

    bdb:  Ignoring log file: .../log.XXXXXXXXXX: unsupported log version #
    

    Bedeutet das, dass die neue BDB-Version das alte Log-Dateiformat nicht unterstützt. In diesem Fall müssen Sie alle BDB-Log-Dateien aus Ihrem Datenbankverzeichnis löschen (die Dateien haben das Format log.XXXXXXXXXX) und mysqld neu starten. Wir empfehlen ausserdem, dass Sie mysqldump --opt auf Ihre alten BDB-Tabellen ausführen, die alten Tabellen löschen und aus dem Dump wiederherstellen.

  • Wenn Sie im auto_commit-Modus fahren und eine Tabelle löschen, die durch einen anderen Thread benutzt wird, erhalten Sie womöglich folgende Fehlermeldungen in der MySQL-Fehlerdatei:

    001119 23:43:56  bdb:  Missing log fileid entry
    001119 23:43:56  bdb:  txn_abort: Log undo failed for LSN: 1 3644744: Invalid
    

    Das ist kein schwerer Fehler, aber wir empfehlen, alle Tabellen zu löschen, wenn Sie nicht im auto_commit-Modus sind, bis dieses Problem behoben ist (die Behebung ist nicht trivial).


This is a translation of the MySQL Reference Manual that can be found at dev.mysql.com. The original Reference Manual is in English, and this translation is not necessarily as up to date as the English version.