Een klant belde me deze week: zijn contactformulier laadde tien seconden voordat er een foutmelding verscheen. De site zelf was snel genoeg. Het thema was recent bijgewerkt. Niets wees op een serverprobleem. Uiteindelijk bleek de database bijna vierhonderd megabyte groot te zijn voor een site met dertig pagina’s en geen webshop. Dat is niet normaal. Dat is een database die jarenlang niet is opgeruimd.
WordPress schrijft veel naar de database. Elke revisie van een pagina, elke tijdelijke optie van een plugin, elke mislukte cronjob laat een spoor achter. Na een paar jaar onderhoud zonder opruiming zit je met een database die tien keer zo groot is als nodig. Dat vertraagt query’s, maakt back-ups zwaarder en zorgt soms voor time-outs op precies het moment dat een klant een formulier verstuurt. Dit stuk legt uit wat er in die database zit, wat je weg kunt gooien en hoe je dat gestructureerd aanpakt.
Wat er in je WordPress-database zit dat je niet nodig hebt
WordPress slaat standaard tien revisies op van elke post of pagina. Schrijf je dertig keer aan een pagina, dan staan er dertig versies in de database. Vermenigvuldig dat met honderd pagina’s en je hebt duizenden rijen in de wp_posts-tabel die niets bijdragen aan de live site.
Naast revisies zijn er de auto-drafts. WordPress slaat elke minuut automatisch een conceptversie op terwijl je typt. Die concepten worden niet altijd opgeruimd als je de pagina publiceert. Ze stapelen zich op in dezelfde tabel als je echte content, maar zijn nooit zichtbaar voor bezoekers.
Dan zijn er de transients. Dat zijn tijdelijke waarden die plugins in de wp_options-tabel parkeren, met een verloopdatum. WordPress ruimt verlopen transients op in theorie, maar in de praktijk blijven ze staan totdat iemand ernaar kijkt. Op sites met veel plugins kan de wp_options-tabel uitgroeien tot tienduizenden rijen, waarvan een groot deel verlopen transients zijn. Elke keer dat WordPress opstart, leest het een deel van die tabel in. Hoe groter de tabel, hoe trager dat gaat.
Hoe je de omvang van het probleem inschat
Voordat je iets verwijdert, wil je weten hoe groot het probleem is. Ga naar phpMyAdmin, kies je database en kijk naar de kolom “Grootte” per tabel. De tabellen die het meest opvallen zijn doorgaans:
- wp_posts — bevat revisies, auto-drafts en prullenbakinhoud
- wp_postmeta — bevat metadata die hoort bij die posts, inclusief weesrijen zonder bovenliggende post
- wp_options — bevat transients, widget-instellingen en plugin-rommel
- wp_actionscheduler_actions — op sites met WooCommerce of bepaalde e-mailplugins kan deze tabel enorm worden
Een gezonde kleine site heeft een database van tien tot dertig megabyte. Zit je op honderd megabyte of meer zonder webshop, dan is er iets aan de hand. Vierhonderd megabyte, zoals bij die klant, betekent dat er jarenlang niets is opgeruimd.
Je kunt ook via SQL kijken hoeveel revisies er zijn:
SELECT COUNT(*) FROM wp_posts WHERE post_status = ‘inherit’ AND post_type = ‘revision’;
Als dat getal in de duizenden loopt, weet je genoeg.
Wat je veilig kunt verwijderen en in welke volgorde
Maak eerst een back-up. Niet als vanzelfsprekende disclaimer, maar omdat je straks SQL-query’s uitvoert die je niet kunt terugdraaien. Een verse dump van de database, lokaal opgeslagen, is het minimale vangnet.
Begin met de prullenbak. Verwijderde posts en pagina’s blijven dertig dagen in de prullenbak staan. Als je die nooit leegt, groeien ze aan. Ga naar Berichten → Prullenbak en leeg hem. Doe hetzelfde voor pagina’s en media.
Verwijder daarna revisies. Je kunt dit via SQL doen:
DELETE FROM wp_posts WHERE post_type = ‘revision’;
DELETE FROM wp_postmeta WHERE post_id NOT IN (SELECT ID FROM wp_posts);
De tweede query ruimt weesrijen op in de metadata-tabel: rijen die horen bij posts die niet meer bestaan. Die blijven anders achter als stille ballast.
Verlopen transients verwijder je zo:
DELETE FROM wp_options WHERE option_name LIKE ‘%_transient_%’ AND option_value < UNIX_TIMESTAMP();
Wees hiermee precies: verwijder alleen verlopen transients, niet alle transients. Actieve transients zijn cachewaarden die plugins bewust hebben opgeslagen. Die gooi je niet zomaar weg.
Daarna optimaliseer je de tabellen. Na grote verwijderingen blijft er lege ruimte in de tabelbestanden staan. MySQL hergebruikt die ruimte niet automatisch. Met OPTIMIZE TABLE pak je die ruimte terug:
OPTIMIZE TABLE wp_posts, wp_postmeta, wp_options;
Dit kan even duren op grote tabellen. Voer het uit op een moment dat er weinig verkeer is.
Revisies beperken zodat het probleem niet terugkomt
Opruimen is zinloos als je het over een jaar opnieuw moet doen. Het slimste wat je kunt doen is het aantal revisies dat WordPress opslaat beperken. Dat doe je in wp-config.php:
define(‘WP_POST_REVISIONS’, 3);
Drie revisies is voor de meeste mkb-sites meer dan genoeg. Je houdt de laatste drie versies van elke pagina als terugvaloptie, maar je laat de database niet volstromen.
Wil je revisies helemaal uitzetten, gebruik dan:
define(‘WP_POST_REVISIONS’, false);
Dat is voor sites waar content zelden wordt bewerkt en waar je de database zo klein mogelijk wilt houden. Webshops met veel productpagina’s die regelmatig worden bijgewerkt laat ik liever op drie revisies staan.
Je kunt ook het interval van auto-saves aanpassen. Standaard slaat WordPress elke zestig seconden op. Voor een site waar de redacteur vijf minuten aan een pagina schrijft voordat hij publiceert, is dat overdreven:
define(‘AUTOSAVE_INTERVAL’, 300);
Dat is vijf minuten. Nog steeds een vangnet, maar minder agressief.
Hoe je dit onderdeel maakt van regulier onderhoud
Eenmalig opruimen helpt, maar het probleem komt terug als je er niets structureels aan doet. De slimste aanpak is dit inbouwen in je maandelijkse onderhoudscyclus.
Wat ik zelf doe:
- Revisies beperken staat in wp-config.php op elke site die ik beheer, dat is een eenmalige instelling
- Eens per kwartaal draai ik een databaseoptimalisatie via een beheerplug-in of direct via phpMyAdmin
- Na grote plugin-updates kijk ik of de wp_options-tabel niet onverwacht is gegroeid
- De wp_actionscheduler-tabel controleer ik op sites met e-mailautomatisering, want die kan snel groot worden als er mislukte taken in blijven staan
Je kunt dit ook automatiseren via een WP-CLI-commando in een cronjob op de server:
wp transient delete –expired –allow-root
wp post delete $(wp post list –post_status=trash –format=ids –allow-root) –allow-root
Dat is iets voor als je servertoegang hebt en weet wat je doet. Op gedeelde hosting met een beheerpaneel doe je het handmatig of via een plug-in die je vertrouwt.
Het punt is niet welke methode je kiest. Het punt is dat je er een methode voor hebt. Een database die nooit wordt opgeruimd groeit gestaag, vertraagt query’s, maakt back-ups zwaarder en zorgt uiteindelijk voor de soort storing waarmee die klant mij belde. Een trage back-up is ook een probleem: als je back-up tien minuten duurt in plaats van twee, is de kans groter dat hij halverwege afbreekt of dat je hem overslaat omdat het te lang duurt.
Kleine sites merken dit minder. Maar ik heb sites beheerd die vijf jaar oud waren, nooit waren opgeruimd, en een database hadden die groter was dan de hele server-back-up van een vergelijkbare site die wel was onderhouden. Dat verschil zit niet in de hoeveelheid content. Dat zit in de rommel die ondertussen is opgestapeld.
Neem een uur de tijd, kijk wat er in je database zit, gooi weg wat je niet nodig hebt en zorg dat het niet zo snel terugkomt. Dat is het soort onderhoud dat je klant nooit ziet, maar dat voorkomt dat hij je belt met een formulier dat niet werkt.