Joomla-Datenbank plötzlich mehrere Gigabyte groß: Session-Tabelle analysieren und bereinigen
Eine Joomla-Datenbank mit mehreren Gigabyte Größe ist zumindest ein Anlass, genauer hinzusehen. In meinem Fall war eine Joomla-Installation mit MariaDB auf rund 3,65 GB angewachsen. Bei der Analyse fiel insbesondere die Session-Tabelle auf.
Dieser Artikel dokumentiert die Schritte, mit denen sich eine solche Tabelle untersuchen und bereinigen lässt. Wichtig: Vor Änderungen an einer produktiven Datenbank sollte immer ein vollständiges Backup vorhanden sein.
Problem: Eine ungewöhnlich große Joomla-Datenbank
Der erste Schritt besteht nicht darin, auf Verdacht Tabellen oder Datensätze zu löschen. Zunächst sollte geklärt werden, welche Tabellen den Speicher tatsächlich belegen.
Mit dieser Abfrage lassen sich die Tabellen einer Datenbank nach ihrer Größe sortieren:
SELECT
table_name,
ROUND((data_length + index_length) / 1024 / 1024, 2) AS size_in_mb
FROM information_schema.tables
WHERE table_schema = 'DATENBANKNAME'
ORDER BY size_in_mb DESC;
DATENBANKNAME muss durch den tatsächlichen Namen der Joomla-Datenbank ersetzt werden.
In meinem Fall gehörte die Joomla-Session-Tabelle zu den auffälligen Tabellen.
Die Joomla-Session-Tabelle untersuchen
Joomla verwendet ein individuell konfiguriertes Tabellenpräfix. Aus einer Tabelle wie
abc_session
kann daher bei einer anderen Installation beispielsweise
xyz_session
werden.
Die Struktur lässt sich mit DESCRIBE anzeigen:
DESCRIBE `abc_session`;
In der untersuchten Joomla-Installation hatte die Session-Tabelle unter anderem folgende Felder:
session_id
client_id
guest
time
data
userid
username
Für die weitere Analyse sind vor allem time und data interessant.
time ist ein Integer-Feld, über das sich alte Session-Einträge identifizieren lassen. data ist ein MEDIUMTEXT-Feld und kann entsprechend umfangreiche Session-Daten enthalten.
Wie groß sind die eigentlichen Session-Daten?
Um zunächst nur die gespeicherten Inhalte des Feldes data zu untersuchen, kann man deren Gesamtlänge ermitteln:
SELECT
SUM(CHAR_LENGTH(data)) AS total_data_size
FROM `abc_session`;
In meinem Fall ergab die Abfrage:
687078044
CHAR_LENGTH() liefert hier die Anzahl der Zeichen, nicht unmittelbar die physische Größe der Tabelle auf dem Datenträger. Bei den vorliegenden Session-Daten entsprach die Größenordnung dennoch bereits mehreren hundert Megabyte Inhalt allein in diesem Feld.
Die tatsächliche Tabellengröße sollte deshalb zusätzlich über information_schema.tables bzw. die Tabelleninformationen von phpMyAdmin kontrolliert werden.
Wie viele alte Sessions gibt es?
Bevor Daten gelöscht werden, kann man zunächst prüfen, welche Datensätze von einer Löschbedingung betroffen wären.
Beispielsweise für Sessions, deren time-Wert älter als zehn Tage ist:
SELECT *
FROM `abc_session`
WHERE `time` < UNIX_TIMESTAMP(NOW() - INTERVAL 10 DAY)
LIMIT 10;
Noch übersichtlicher ist zunächst die reine Anzahl:
SELECT COUNT(*)
FROM `abc_session`
WHERE `time` < UNIX_TIMESTAMP(NOW() - INTERVAL 10 DAY);
Damit lässt sich kontrollieren, wie viele Datensätze die Bedingung überhaupt erfasst.
Wichtig: Der Zeitraum von zehn Tagen ist hier ein Beispiel aus der konkreten Bereinigung und keine allgemeingültige Joomla-Empfehlung. Welche Sessions gelöscht werden können, sollte zur Session-Konfiguration der jeweiligen Installation passen.
Alte Session-Einträge löschen
Ist geklärt, dass die entsprechenden Datensätze entfernt werden sollen, lautet die Abfrage beispielsweise:
DELETE FROM `abc_session`
WHERE `time` < UNIX_TIMESTAMP(NOW() - INTERVAL 10 DAY);
Bei sehr vielen Datensätzen kann eine solche Abfrage über phpMyAdmin allerdings problematisch werden. Bei der untersuchten Installation kam es bei einer größeren Operation zu einem HTTP-500-Fehler bzw. einem Verbindungsabbruch.
In einem solchen Fall kann es sinnvoll sein, nicht Hunderttausende Datensätze in einer einzigen Operation zu bearbeiten, sondern die Löschung in kleineren Portionen durchzuführen:
DELETE FROM `abc_session`
WHERE `time` < UNIX_TIMESTAMP(NOW() - INTERVAL 10 DAY)
LIMIT 1000;
Der Befehl kann wiederholt ausgeführt werden, bis keine entsprechenden Datensätze mehr vorhanden sind.
In der konkreten Datenbank wurden schließlich rund 300.000 Session-Datensätze entfernt.
Warum wird die Datenbank nach dem Löschen kaum kleiner?
Das war der überraschende Teil: Obwohl rund 300.000 Datensätze gelöscht worden waren, sank die angezeigte Gesamtgröße der Datenbank zunächst nur geringfügig.
Das bedeutet nicht, dass MariaDB die gelöschten Datensätze in einem „Papierkorb“ aufbewahrt.
Bei InnoDB führt ein DELETE jedoch nicht zwangsläufig dazu, dass der zuvor von einer Tabelle belegte Speicherplatz unmittelbar als kleinere Tabellendatei sichtbar wird. Frei gewordener Platz kann zunächst innerhalb der Tabelle wiederverwendbar bleiben.
Deshalb kann nach einer großen Löschaktion eine Neuorganisation der Tabelle sinnvoll sein.
Tabelle mit OPTIMIZE TABLE neu organisieren
Dazu kann man ausführen:
OPTIMIZE TABLE `abc_session`;
Bei der untersuchten InnoDB-Tabelle meldete MariaDB daraufhin:
Table does not support optimize, doing recreate + ...
Diese Meldung ist in diesem Zusammenhang nicht automatisch ein Fehler. MariaDB weist damit darauf hin, dass die Optimierung bei dieser Tabelle über einen Neuaufbau erfolgt.
Gerade bei einer großen Tabelle sollte man berücksichtigen, dass ein solcher Vorgang erheblich aufwendiger sein kann als ein gewöhnliches DELETE.
Größe anschließend erneut kontrollieren
Nach der Bereinigung kann die Tabellengröße erneut abgefragt werden:
SELECT
table_name,
ROUND(data_length / 1024 / 1024, 2) AS data_mb,
ROUND(index_length / 1024 / 1024, 2) AS index_mb,
ROUND((data_length + index_length) / 1024 / 1024, 2) AS total_mb
FROM information_schema.tables
WHERE table_schema = 'DATENBANKNAME'
ORDER BY (data_length + index_length) DESC;
Das ist auch für die weitere Analyse nützlich: Statt wahllos Joomla-Tabellen zu bereinigen, sieht man sofort, welche Tabellen tatsächlich relevant für die Gesamtgröße sind.
Ein zusätzlicher Joomla-Schalter: „Track Guest Session Metadata“
Bei der Analyse fiel außerdem die Joomla-Einstellung „Track Guest Session Metadata“ auf.
Da die untersuchte Installation gerade durch sehr viele Session-Datensätze auffällig geworden war, ist diese Einstellung ein naheliegender Punkt für die weitere Ursachenanalyse. Aus der hier beschriebenen Untersuchung allein lässt sich allerdings nicht belegen, dass diese Option das starke Wachstum verursacht hat.
Deshalb sollte man sie nicht allein aufgrund der Datenbankgröße deaktivieren, sondern zunächst prüfen, ob und wofür die Installation Gast-Session-Metadaten benötigt.
Was sich aus der Analyse ableiten lässt
Die wichtigste Erkenntnis war weniger ein einzelner SQL-Befehl als die Reihenfolge der Fehlersuche:
- Zuerst die tatsächlichen Größen aller Tabellen ermitteln.
- Bei einer auffälligen Session-Tabelle Struktur und Anzahl der Datensätze prüfen.
- Den Umfang des Feldes
datauntersuchen. - Alte Datensätze zunächst nur per
SELECTbzw.COUNT(*)identifizieren. - Erst danach gezielt löschen.
- Bei sehr großen Datenmengen gegebenenfalls in kleineren Blöcken arbeiten.
- Nicht erwarten, dass ein
DELETEbei InnoDB die sichtbare Tabellengröße sofort entsprechend reduziert. - Nach größeren Löschaktionen prüfen, ob eine Neuorganisation der Tabelle erforderlich ist.
Vor allem sollte man nicht anfangen, vermeintlich alte Joomla- oder Erweiterungstabellen auf Verdacht zu löschen. Dass eine Tabelle groß, deaktiviert oder historisch gewachsen ist, beweist noch nicht, dass sie für die aktuelle Installation entbehrlich ist.
Die Session-Tabelle ist dagegen ein gutes Beispiel dafür, wie man eine auffällige Datenmenge zunächst nachvollziehbar analysieren kann, bevor man in die Struktur einer produktiven Joomla-Datenbank eingreift.