LW IT Solutions
« Blog Overview /WordPress-Plugins & Tricks/Tutorials / Automatisiertes Datenbank-Cleaning via WP-CLI und Server-Cronjob
This post in other languages:

Automatisiertes Datenbank-Cleaning via WP-CLI und Server-Cronjob

Automatisiertes Datenbank-Cleaning via WP-CLI und Server-Cronjob
Inhalt
  1. Architektur-Überblick: Datenbank-Fragmentierung in WordPress
  2. Schritt-für-Schritt-Implementierungsanleitung
  3. Zusammenfassung und resultierender Mehrwert
  4. Fragen und Antworten
  5. Quellen

Architektur-Überblick: Datenbank-Fragmentierung in WordPress

Mit wachsender Lebensdauer einer WordPress-v7.0.2-Installation unterliegt die zugrundeliegende MySQL- oder MariaDB-Datenbank einer erheblichen Fragmentierung und Datenblähung. Jedes redaktionelle Speichern erzeugt einen neuen Eintrag in der Tabelle wp_posts als Beitragsrevision. Gleichzeitig schreiben Plugins und Themes regelmäßig temporäre Cache-Daten als sogenannte Transients in die Tabelle wp_options. Nach Ablauf der Gültigkeit löscht WordPress diese Transients standardmäßig träge während regulärer HTTP-Anfragen, wodurch oft Tausende veralteter Zeilen verbleiben.

Darüber hinaus hinterlässt das Löschen von Artikeln oder Custom Post Types ohne explizite Bereinigungsroutinen verwaiste Metadaten in der Tabelle wp_postmeta. Diese unkontrollierte Ansammlung vergrößert die Datenbank-Indizes, verlangsamt die Ausführungszeit komplexer SELECT-Abfragen und erhöht den Arbeitsspeicherbedarf des Datenbankservers. Eine automatisierte Bereinigung über WP-CLI und Server-Cronjobs umgeht den Webserver-Stack vollständig und sorgt für eine hochperformante, blockierungsfreie Wartung ohne PHP-Laufzeitbegrenzungen.

Gestapelter Vorher-Nachher-Vergleich einer WordPress-Datenbank mit den fünf Aufräumschritten dazwischen
Vier Sorten Ballast machen den Großteil einer gewachsenen WordPress-Datenbank aus. Das wöchentliche Skript räumt sie in fester Reihenfolge ab und defragmentiert danach — übrig bleibt der Inhalt, der wirklich ausgeliefert wird.

Schritt-für-Schritt-Implementierungsanleitung

Schritt 1: Analyse der Datenbank-Größe und CLI-Audit

Vor der Ausführung von Löschroutinen sollte die aktuelle Größe und Struktur der Datenbank über eine SSH-Verbindung mittels WP-CLI analysiert werden. Der folgende Befehl listet alle Tabellen absteigend nach ihrer Speichergröße in Megabyte auf:

wp db size --tables --human-readable

Um die genaue Anzahl der aktuell in der Options-Tabelle verbliebenen, abgelaufenen Transients zu ermitteln, kann eine erste Diagnoseabfrage ausgeführt werden:

wp db query "SELECT COUNT(*) FROM wp_options WHERE option_name LIKE '_transient_timeout_%' AND option_value < UNIX_TIMESTAMP();"

Schritt 2: Entwicklung des automatisierten Wartungs-Skripts

Um veraltete Daten sicher zu eliminieren, ohne auf Ressourcen verbrauchende Drittanbieter-Plugins angewiesen zu sein, eignet sich ein dediziertes Shell-Skript auf Basis von WP-CLI und direkten SQL-Befehlen. Das Skript adressiert vier Hauptursachen für Datenbank-Bloat:

  • Abgelaufene Transients: Entfernt alle ungültigen Cache-Einträge aus wp_options.
  • Veraltete Beitragsrevisionen: Bereinigt historische Revisions-Objekte aus wp_posts.
  • Verwaiste Postmeta-Einträge: Führt eine relationale DELETE-Abfrage aus, um Metadaten zu löschen, deren übergeordneter Post-ID-Eintrag nicht mehr existiert.
  • Verwaiste Taxonomie-Verknüpfungen: Entfernt Zuordnungen in wp_term_relationships, deren zugehöriger Beitrag nicht mehr existiert. Mit Polylang oder mit Taxonomien für andere Objekttypen löscht die Abfrage auch Zuordnungen, die gar keinem Beitrag gelten, etwa die Sprachzuordnungen der Rubriken und Schlagwörter; Näheres unter „Fragen und Antworten“.

Das folgende produktionsreife Skript kann auf dem Server unter /opt/scripts/wp-db-cleanup.sh abgelegt werden:

#!/usr/bin/env bash
# ============================================================================
# Hochperformantes WordPress-Datenbank-Bereinigungsskript
# Zielsystem: WordPress v7.0.2 via WP-CLI
# ============================================================================

WP_PATH="/var/www/lukaswojcik.com/htdocs"
LOG_FILE="/var/log/wp_db_cleanup.log"

echo "[$(date +'%Y-%m-%d %H:%M:%S')] Wartungszyklus gestartet..." >> "$LOG_FILE"

# 1. Alle abgelaufenen Transients löschen
wp transient delete --expired --path="$WP_PATH" >> "$LOG_FILE" 2>&1

# 2. Alle Beitragsrevisionen löschen (optional: Limitierung auf die letzten 3)
REVISIONS=$(wp post list --post_type=revision --format=ids --path="$WP_PATH")
if [ -n "$REVISIONS" ]; then
    wp post delete $REVISIONS --force --path="$WP_PATH" >> "$LOG_FILE" 2>&1
fi

# 3. Verwaiste Postmeta-Einträge via direkte relationale SQL-Abfrage löschen
wp db query "DELETE pm FROM wp_postmeta pm LEFT JOIN wp_posts wp ON wp.ID = pm.post_id WHERE wp.ID IS NULL;" --path="$WP_PATH" >> "$LOG_FILE" 2>&1

# 4. Verwaiste Taxonomie-Verknüpfungen entfernen
# Achtung: löscht mit Polylang auch Sprachzuordnungen von Termen (object_id = Term-ID)
wp db query "DELETE tr FROM wp_term_relationships tr LEFT JOIN wp_posts wp ON wp.ID = tr.object_id WHERE wp.ID IS NULL;" --path="$WP_PATH" >> "$LOG_FILE" 2>&1

# 5. MySQL/MariaDB-Speicher-Engines defragmentieren und optimieren
wp db optimize --path="$WP_PATH" >> "$LOG_FILE" 2>&1

echo "[$(date +'%Y-%m-%d %H:%M:%S')] Wartungszyklus erfolgreich beendet." >> "$LOG_FILE"

Schritt 3: Zuweisung strikter Datei-Berechtigungen

Um unbefugte Ausführungen zu verhindern, müssen dem Shell-Skript restriktive Unix-Dateirechte zugewiesen werden. Die Ausführung sollte ausschließlich dem Administrations-Benutzer oder dem Systemkonto des Webservers gestattet sein:

chmod 700 /opt/scripts/wp-db-cleanup.sh
chown www-data:www-data /opt/scripts/wp-db-cleanup.sh

Schritt 4: Automatisierung mittels Server-Cronjob

Im Gegensatz zum standardmäßigen WP-Cron, der auf eingehenden HTTP-Verkehr angewiesen ist und auf Seiten mit geringem Traffic verzögert auslösen kann, garantiert ein nativer Linux-Cronjob die Ausführung zu präzisen Zeitpunkten. Um die Bereinigung jeden Sonntag um 03:00 Uhr morgens ausführen zu lassen, wird die Crontab-Konfiguration bearbeitet:

crontab -e -u www-data

Folgende Zeitplan-Zeile wird am Ende der Crontab-Datei hinzugefügt:

0 3 * * 0 /bin/bash /opt/scripts/wp-db-cleanup.sh >/dev/null 2>&1

Schritt 5: Qualitätssicherung und Verifikation

Nach einer manuellen Testausführung des Skripts sollte die erfolgreiche Bereinigung über Terminal-Befehle verifiziert werden:

  1. Prüfung der Logfiles: Kontrolle der Datei `/var/log/wp_db_cleanup.log` auf Abwesenheit von Syntax-Fehlern oder Datenbank-Locks.
  2. Validierung der Tabellen-Optimierung: Ausführung von `wp db size –human-readable` zur Bestätigung des reduzierten Speicherbedarfs von `wp_postmeta` und `wp_posts`.
  3. Integritätsprüfung im Frontend: Sicherstellen, dass aktive Artikel, eigene Toolbox-Skripte und Polylang-Sprachbeziehungen fehlerfrei und ohne fehlende Metadaten geladen werden.

Zusammenfassung und resultierender Mehrwert

Was sich damit erreichen lässt: Der vollständige Verzicht auf manuelle Datenbankbereinigungen und ressourcenintensive Optimierungs-Plugins zugunsten einer autonomen, auf Serverebene operierenden Wartungs-Pipeline mittels WP-CLI und Linux-Cronjobs.

Resultierender Mehrwert:

  • Dauerhaft schlanke Datenbankstruktur: Relationale Tabellen bleiben defragmentiert und frei von verwaisten Metadaten, wodurch die Gesamtgröße der Datenbank bei aktiven Publikationssystemen um 40–60 % sinkt.
  • Beschleunigte SQL-Ausführungsgeschwindigkeit: Bereinigte Indizes reduzieren die Ausführungszeit für dynamische Dashboard-Aufrufe und komplexe JOIN-Abfragen signifikant.
  • Null PHP-Ressourcenbelastung: Die Ausführung außerhalb des Webserver-Kontexts verhindert HTTP-Timeouts, Arbeitsspeicherspitzen und Ladezeitverzögerungen für Besucher im Frontend.

Fragen und Antworten

Warum läuft das Skript von Hand fehlerfrei, aus dem Cronjob aber nicht?

Meist wegen einer anderen Umgebung. Cron startet Befehle mit einer knappen Umgebung, und drei Unterschiede sind die häufigsten Ursachen:

  1. Der Suchpfad. Cron setzt PATH in der Regel nur auf /usr/bin:/bin. Liegt WP-CLI, wie oft, unter /usr/local/bin/wp, findet das Skript den Befehl wp nicht. Abhilfe schafft ein vollständiger Pfad im Skript oder eine PATH-Zeile am Anfang der Crontab.
  2. Die Schreibrechte der Logdatei. Das Skript läuft als www-data und schreibt nach /var/log/wp_db_cleanup.log, in ein Verzeichnis, das für www-data üblicherweise nicht beschreibbar ist. Scheitert die Umleitung in die Logdatei, führt die Shell den betreffenden Befehl gar nicht erst aus; die Datenbank bleibt also unberührt. Die Datei muss deshalb vorher angelegt und www-data übergeben werden, oder das Log liegt an einem Ort, an dem www-data schreiben darf.
  3. Die verschluckte Ausgabe. Die Crontab-Zeile leitet alles nach /dev/null. Die Fehlermeldungen der gescheiterten Umleitungen verschwinden dort, und der Lauf wirkt still erfolgreich.

Ein Probelauf unter denselben Bedingungen zeigt diese Fehler vorab, etwa mit sudo -u www-data env -i PATH=/usr/bin:/bin /bin/bash /opt/scripts/wp-db-cleanup.sh. Läuft das Skript so durch, sind die häufigsten Ursachen ausgeschlossen.

Ist die Abfrage für verwaiste Taxonomie-Verknüpfungen auf jeder Installation sicher?

Nein. Die Tabelle wp_term_relationships verknüpft Terme nicht nur mit Beiträgen. Eine Taxonomie kann für andere Objekttypen registriert sein, etwa für Benutzer oder für die alten Links aus wp_links; dann steht in object_id keine Beitrags-ID. Mehrsprachigkeits-Plugins wie Polylang ordnen außerdem Rubriken und Schlagwörter über diese Tabelle ihrer Sprache und ihren Übersetzungen zu, mit der Term-ID als object_id.

Die Abfrage aus dem Skript löscht jede Zeile, deren object_id in wp_posts fehlt, und trifft damit genau diese Zuordnungen. Tückisch ist, dass sie nicht alle trifft: Eine Term-ID, die zufällig auch als Beitrags-ID existiert, bleibt stehen. Das Ergebnis sind vereinzelte Rubriken ohne Sprache oder ohne Übersetzung, verstreut und schwer zu erklären.

Sicherer ist eine Einschränkung auf die Taxonomien, die tatsächlich an Beiträgen hängen, über einen JOIN auf wp_term_taxonomy und eine Liste wie category und post_tag. Vor jedem Löschlauf ist außerdem eine Sicherung nötig, etwa mit wp db export, und ein Probelauf mit SELECT COUNT(*) statt DELETE zeigt, wie viele Zeilen betroffen wären.

Was bewirkt wp db optimize auf InnoDB-Tabellen?

InnoDB kennt kein eigenes Optimieren. MySQL und MariaDB bauen die Tabelle stattdessen neu auf und aktualisieren ihre Statistiken; die Meldung dazu lautet „Table does not support optimize, doing recreate + analyze instead“. Für den Neuaufbau braucht der Server vorübergehend etwa so viel freien Plattenplatz, wie die Tabelle belegt, und große Tabellen brauchen entsprechend lange.

Kleiner wird die Datei nur, wenn jede Tabelle eine eigene Datei hat (innodb_file_per_table, in aktuellen Versionen Standard). Liegen die Tabellen im gemeinsamen Systemtablespace, bleibt dessen Datei gleich groß. Nach einer großen Löschaktion lohnt der Neuaufbau; als wöchentliche Routine bringt er wenig, weil InnoDB frei gewordenen Platz innerhalb der Tabelle ohnehin wiederverwendet.

Lässt sich die Zahl der Revisionen begrenzen, statt sie jede Woche vollständig zu löschen?

Ja, mit der Konstante WP_POST_REVISIONS in der wp-config.php, etwa define( 'WP_POST_REVISIONS', 3 );. WordPress entfernt dann beim nächsten Speichern eines Beitrags dessen älteste Revisionen über die Grenze hinaus. Die Versionsgeschichte bleibt so in begrenztem Umfang erhalten, statt jede Woche vollständig gelöscht zu werden.

Lukas Wojcik

Lukas Wojcik

Systems architect and technology enthusiast specializing in scalable tracking solutions, GMP Stack (GA4 & GTM), and robust backend architectures. Advocate for clean code and privacy-first design.

Get in Touch

Briefly describe your project or inquiry for a tailored response. This site is protected by reCAPTCHA.

Kommentar schreiben

Erfahrungen mit anderen Plugins oder Hosting-Umgebungen und Rückfragen zur Einrichtung sind hier willkommen.

Die E-Mail-Adresse wird nicht veröffentlicht. Pflichtfelder sind mit einem Stern versehen.

ALL ARTICLES & CATEGORIES

CCTV

Diese Rubrik per RSS verfolgen

Cloud & AI

Diese Rubrik per RSS verfolgen

Data Privacy

Alle 16 Artikel dieser Rubrik Diese Rubrik per RSS verfolgen

Digital Analytics

Alle 53 Artikel dieser Rubrik Diese Rubrik per RSS verfolgen

Digital Marketing

Alle 36 Artikel dieser Rubrik Diese Rubrik per RSS verfolgen

IT & Networks

Alle 17 Artikel dieser Rubrik Diese Rubrik per RSS verfolgen

Music Production

Alle 13 Artikel dieser Rubrik Diese Rubrik per RSS verfolgen

Raspberry Pi

Diese Rubrik per RSS verfolgen

Smart Home

Alle 18 Artikel dieser Rubrik Diese Rubrik per RSS verfolgen

Web Entwicklung

Diese Rubrik per RSS verfolgen

WordPress-Plugins & Tricks

Diese Rubrik per RSS verfolgen