WordPress database onderhoud: revisies, verweesde postmeta en opgeblazen tabellen opschonen

WordPress verzamelt berichtrevisies, verlopen transienten, verweesde postmeta, verwijderde berichten en automatische concepten. Een site die jarenlang draait kan een database hebben die twee keer zo groot is als nodig. Deze gids loopt door elk type afval, hoe je het veilig verwijdert met WP-CLI en SQL-queries, hoe je revisies beperkt voor de toekomst, en hoe je OPTIMIZE TABLE uitvoert zonder productieverkeer te blokkeren.

Een WordPress-database groeit op twee manieren: bewuste content (berichten, pagina's, producten, reacties) en opgehoopt afval (revisies van elk opgeslagen concept, verlopen transienten die nooit worden opgeruimd, metadata voor berichten die niet meer bestaan, automatische concepten die nooit zijn gepubliceerd). Op een site die drie jaar of langer draait, kan het afval zwaarder wegen dan de content. De database werkt nog steeds — MySQL maakt het niet uit — maar backups duren langer, migraties verplaatsen meer data dan nodig, en queries op opgeblazen tabellen zijn trager dan ze hoeven te zijn.

Dit artikel behandelt het afval, niet de queries. Als het probleem trage queryuitvoering is op een database die al de juiste grootte heeft, behandelt het artikel over trage databases dat. Als het probleem specifiek de wp_options-tabel en autoloaded data is, gaat het artikel over autoloaded data dieper in op die ene tabel.

Wat zich ophoopt in een WordPress-database

Berichtrevisies

WordPress slaat een revisie op elke keer dat je op Concept opslaan of Bijwerken klikt bij een bericht of pagina. Standaard is er geen limiet. Een bericht dat 200 keer is bewerkt heeft 200 revisies, elk opgeslagen als een volledige rij in wp_posts met een eigen set rijen in wp_postmeta. Op een WooCommerce-winkel genereren producten ook revisies.

Verlopen transienten

Transienten zijn tijdelijke sleutel-waardeparen opgeslagen in wp_options (of in een object-cachebackend als er een actief is). Plugins gebruiken ze om API-responses, licentiecontroles en berekende data te cachen. Wanneer een transient verloopt, verwijdert WordPress die niet proactief. Het verwijdert een verlopen transient alleen wanneer iets die uitleest. Op een site met weinig verkeer en veel plugins hopen verlopen transienten zich oneindig op.

Verweesde postmeta

Wanneer een bericht definitief wordt verwijderd, verwijdert WordPress de wp_posts-rij maar ruimt niet altijd de bijbehorende rijen in wp_postmeta op. Plugins die aangepaste velden voor berichten opslaan laten vooral vaak wezen achter. Na verloop van tijd verzamelt wp_postmeta rijen die verwijzen naar post_id-waarden die niet meer bestaan.

Automatische concepten en verwijderde berichten

WordPress maakt een automatisch concept aan telkens wanneer je op "Nieuw toevoegen" klikt bij een bericht of pagina. Als je wegnavigert zonder te publiceren, blijft het concept staan. WordPress heeft een ingebouwde opruiming voor automatische concepten ouder dan 7 dagen via wp_delete_auto_drafts(), maar deze draait op het wp_scheduled_auto_draft_delete cron-event. Als WP-Cron verkeerd is geconfigureerd of uitgeschakeld, hopen automatische concepten zich op.

Verwijderde berichten zitten 30 dagen in de prullenbak (geregeld door EMPTY_TRASH_DAYS in wp-config.php) voordat ze automatisch worden verwijderd. Als de cron niet draait, blijven ze oneindig staan.

Tabelfragmentatie

InnoDB-tabellen fragmenteren na verloop van tijd naarmate rijen worden ingevoegd, bijgewerkt en verwijderd. Het tabelbestand op schijf groeit maar krimpt niet wanneer rijen worden verwijderd. De data is niet verloren of beschadigd — de ruimte wordt uiteindelijk hergebruikt voor nieuwe rijen — maar gefragmenteerde tabellen gebruiken meer schijfruimte en meer buffer pool-geheugen dan nodig.

Revisies beperken en verwijderen

Revisies beperken voor de toekomst

Voeg toe aan wp-config.php:

define('WP_POST_REVISIONS', 5);

Dit beperkt elk bericht tot 5 revisies. WordPress bewaart de 5 meest recente en stopt met nieuwe aanmaken totdat oudere worden verdrongen. Stel in op false om revisies volledig uit te schakelen (niet aanbevolen — revisies zijn een vangnet voor contentherstel).

Bestaande overtollige revisies verwijderen met WP-CLI

WP-CLI is de veiligste niet-interactieve manier om de database op te schonen.

# Bestaande revisies tellen
wp post list --post_type=revision --format=count

# Alle revisies verwijderen
wp post delete $(wp post list --post_type=revision --format=ids) --force

Voor grote sites met tienduizenden revisies, batch de verwijdering om PHP-geheugenlimieten te vermijden:

wp post list --post_type=revision --format=ids --posts_per_page=500 | xargs wp post delete --force

Herhaal dit totdat het aantal nul bereikt.

Verweesde postmeta veilig verwijderen

Verweesde postmeta-rijen verwijzen naar post_id-waarden die niet meer bestaan in wp_posts. Deze query identificeert ze:

SELECT COUNT(*)
FROM wp_postmeta
WHERE post_id NOT IN (SELECT ID FROM wp_posts);

Als het aantal significant is, verwijder ze:

DELETE FROM wp_postmeta
WHERE post_id NOT IN (SELECT ID FROM wp_posts);

Maak altijd een backup van de database voordat je DELETE-queries uitvoert. Een enkele WHERE-clausefout kan productiedata wissen.

Op WooCommerce-winkels met de HPOS (High-Performance Order Storage)-functie ingeschakeld, staan ordergegevens in aangepaste tabellen (wp_wc_orders, wp_wc_orders_meta) in plaats van wp_posts/wp_postmeta. Queries voor het opschonen van wezen moeten rekening houden met beide opslagsystemen. Zie de WooCommerce database-optimalisatiegids voor HPOS-specifieke opschoning.

Verlopen transienten: wat ze zijn en hoe je ze opruimt

Controleer hoeveel verlopen transienten er zijn:

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

Verlopen transienten verwijderen:

wp transient delete --expired

Of via SQL:

DELETE a, b FROM wp_options a
INNER JOIN wp_options b ON b.option_name = REPLACE(a.option_name, '_transient_timeout_', '_transient_')
WHERE a.option_name LIKE '_transient_timeout_%'
AND a.option_value < UNIX_TIMESTAMP();

Als de site een object-cachebackend gebruikt (Redis, Memcached), worden transienten daar opgeslagen in plaats van in wp_options, en worden verlopen items afgehandeld door het TTL-mechanisme van de cachebackend. In dat geval is het opschonen van wp_options-transienten niet nodig.

Automatische concepten en verwijderde berichten

Automatische concepten verwijderen

wp post delete $(wp post list --post_type=any --post_status=auto-draft --format=ids) --force

Prullenbak legen

wp post delete $(wp post list --post_type=any --post_status=trash --format=ids) --force

Controleer of WP-Cron draait

Het opruimen van automatische concepten en prullenbak is afhankelijk van WP-Cron. Controleer of het werkt:

wp cron event list | grep -E "auto_draft|trash"

Als deze events ontbreken of achterstallig zijn, is WP-Cron mogelijk uitgeschakeld of geblokkeerd. Controleer wp-config.php op DISABLE_WP_CRON en verifieer dat de wp-cron.php-URL extern bereikbaar is.

OPTIMIZE TABLE veilig uitvoeren

OPTIMIZE TABLE claimt ongebruikte ruimte in InnoDB-tabellen terug en defragmenteert het databestand. Op MySQL 8.0 en MariaDB 10.6+ wordt deze operatie uitgevoerd met een online DDL-algoritme dat de tabel niet vergrendelt voor lees- of schrijfoperaties. Op oudere versies kan de tabel kort worden vergrendeld.

Controleer welke tabellen baat zouden hebben:

SELECT TABLE_NAME,
       ROUND(DATA_LENGTH / 1024 / 1024, 2) AS data_mb,
       ROUND(DATA_FREE / 1024 / 1024, 2) AS free_mb
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
  AND DATA_FREE > 0
ORDER BY DATA_FREE DESC;

Tabellen met significante free_mb-waarden hebben terug te winnen ruimte. Optimaliseer de grootste overtreders:

OPTIMIZE TABLE wp_posts;
OPTIMIZE TABLE wp_postmeta;
OPTIMIZE TABLE wp_options;

Voer op een productiesite OPTIMIZE TABLE uit tijdens een rustig moment. Ook al vergrendelt MySQL 8.0+ de tabel niet, de operatie verbruikt I/O en kan tijdelijk de querylatentie verhogen.

WP-CLI gebruiken voor niet-interactief database-onderhoud

Een compleet opschoonscript met WP-CLI:

#!/bin/bash
set -e

echo "=== WordPress Database Opschoning ==="

echo "Berichtrevisies verwijderen..."
wp post delete $(wp post list --post_type=revision --format=ids --posts_per_page=1000) --force 2>/dev/null || echo "Geen revisies gevonden"

echo "Automatische concepten verwijderen..."
wp post delete $(wp post list --post_type=any --post_status=auto-draft --format=ids) --force 2>/dev/null || echo "Geen automatische concepten gevonden"

echo "Prullenbak legen..."
wp post delete $(wp post list --post_type=any --post_status=trash --format=ids) --force 2>/dev/null || echo "Prullenbak is leeg"

echo "Verlopen transienten verwijderen..."
wp transient delete --expired

echo "Spam-reacties verwijderen..."
wp comment delete $(wp comment list --status=spam --format=ids) --force 2>/dev/null || echo "Geen spam-reacties"

echo "Tabellen optimaliseren..."
wp db optimize

echo "Klaar."

Een onderhoudsschema opzetten

Database-afval is een terugkerend probleem. Zonder schema wordt het opschonen vergeten en groeit de database binnen maanden terug naar zijn vorige omvang.

Maandelijks: voer het WP-CLI-opschoonscript hierboven uit. Controleer wp_postmeta op wezengroei. Verwijder verlopen transienten.

Na elke grote contentoperatie (bulkimport, migratie, plugin-deïnstallatie): voer opschoning van verweesde postmeta en OPTIMIZE TABLE uit op betrokken tabellen.

Permanent: stel WP_POST_REVISIONS in wp-config.php in om revisies te beperken tot 5–10 per bericht. Dit is de meest effectieve preventieve maatregel.

Wat database-opschoning NIET is

  • Geen vervanging voor query-optimalisatie. Opschonen verkleint de database maar lost geen trage queries op die worden veroorzaakt door ontbrekende indexen, N+1-querypatronen of dure plugincode. Als de database klein is en nog steeds traag, zijn de queries het probleem, niet de data. Zie het artikel over trage databases.
  • Niet risicovrij wanneer alleen met plugins gedaan. WP-Optimize, Advanced Database Cleaner en vergelijkbare plugins roepen OPTIMIZE TABLE en bulkverwijderingsoperaties aan. Op een productiesite verbruiken deze operaties I/O en moeten ze draaien tijdens rustige momenten. De plugins zelf zijn prima; de timing is wat telt.
  • Geen eenmalige taak. Zonder revisielimieten en een onderhoudsschema groeit de database binnen maanden terug naar zijn opgeblazen staat. Het opschonen is slechts de helft van de oplossing; de limieten en het schema zijn de andere helft.

Klaar met terugkerende traagheid?

Traagheid komt vaak terug na snelle fixes. Professioneel onderhoud houdt updates, caching en limieten consequent op orde.

Bekijk WordPress onderhoud

Doorzoek deze site

Begin met typen om te zoeken, of blader door de kennisbank en blog.