Databasen er ofte en af de første dele af WordPress, der bliver langsom, fordi den vokser med alt: indlæg, produkter, ordrer, plugins’ indstillinger og data, som ingen rydder op i. Typiske tegn er et kontrolpanel, der hakker, produktfiltre, der tænker længe, og sider, der er langsomme, selv når serveren ellers har luft.
Her gennemgår vi, hvordan du finder ud af, om det er databasen, og hvad du så gør ved det, i den rækkefølge det som regel betaler sig. Vil du først have overblikket over, hvordan WordPress er bygget op, så start der.
Er det databasen?
Gæt ikke. Installér Query Monitor, helst på en kopi af siden, og åbn en af de langsomme sider. Det viser, hvor mange forespørgsler siden laver, hvor lang tid de tager tilsammen, hvilke der er langsomst, og hvilket plugin eller tema der står bag hver af dem. Går en stor del af svartiden i databasen, er du det rigtige sted. Går den i PHP, er det koden, der skal ses på.
Query Monitor ser kun den side, du selv åbner. For at fange det, der er langsomt for alle andre, kan du slå MySQL’s slow query log til. Den skriver hver forespørgsel, der tager længere end en grænse, du vælger, ned i en fil:
# my.cnf / mariadb.cnf
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 0.5På delt hosting har du sjældent adgang til den fil, men mange udbydere kan slå loggen til for dig.
De tunge forespørgsler
Ofte er det ikke mange lidt langsomme forespørgsler, men få meget langsomme, der trækker tiden. Og de ligner ofte hinanden.
En typisk synder er et filter på værdien af et felt. Alle ekstra felter ligger i wp_postmeta, og værdikolonnen er ikke indekseret. En meta_query, der leder efter produkter med en bestemt farve eller sorterer efter et brugerdefineret felt, tvinger databasen til at læse alle rækker med den nøgle og sammenligne dem én for én. Med få hundrede produkter mærker ingen det. Med titusindvis bliver det sekunder. Søgninger med LIKE '%ord%' har samme problem, fordi et indeks ikke kan bruges, når søgeordet kan stå hvor som helst i teksten.
Den næste er lister uden grænse. posts_per_page sat til -1 henter alt, og det er fint på en blog med tyve indlæg, men ikke i en butik. Og selv når listen er begrænset, tæller WordPress som standard det samlede antal resultater for at kunne vise sidetal. Har du ikke brug for sidetal, kan du slå optællingen fra og kun hente det, du skal bruge:
$q = new WP_Query( [
'post_type' => 'product',
'posts_per_page' => 12,
'no_found_rows' => true, // ingen optælling, når der ikke er sidetal
'fields' => 'ids', // kun id'er, hvis resten hentes fra cache
] );WooCommerce har selv gjort meget for at komme uden om wp_postmeta. Pris, lagerstatus og bedømmelser ligger også i opslagstabellen wc_product_meta_lookup, som filtre og sortering bruger, og ordrer ligger i deres egne tabeller med High-Performance Order Storage. Er din butik ældre og kører stadig ordrer i wp_posts, kan du skifte under WooCommerce → Indstillinger → Avanceret → Funktioner. Den største gevinst kommer derfor ofte fra at finde det plugin, der stadig laver sine egne tunge meta-opslag, og få det rettet eller skiftet ud.
Indekser: hvad WordPress har, og hvad det mangler
WordPress opretter indekser på det, kernen selv slår op på: post_id og meta_key i wp_postmeta, typen og status i wp_posts og så videre. Værdien i wp_postmeta er ikke indekseret, og det er det, de tunge filtre rammer. Før du tilføjer noget, så se, hvad databasen faktisk gør med forespørgslen. Kopiér den fra Query Monitor og sæt EXPLAIN foran:
EXPLAIN SELECT post_id FROM wp_postmeta
WHERE meta_key = 'farve' AND meta_value = 'blå';
-- Læser den mange rækker, kan et samlet indeks hjælpe:
ALTER TABLE wp_postmeta ADD INDEX key_value (meta_key(191), meta_value(100));Kolonnen rows i resultatet viser, hvor mange rækker databasen regner med at læse. Kør EXPLAIN igen efter ændringen, og tag en backup først: på en stor tabel kan det tage et stykke tid at bygge indekset. Pluginnet Index WP MySQL For Speed tilføjer et sæt indekser lavet til WordPress’ tabeller til de tabeller, hvis du ikke vil skrive dem selv.
wp_options og autoload
Indstillinger, der er markeret til automatisk indlæsning, hentes på hver eneste request, uanset om siden bruger dem. Plugins, der gemmer logfiler, statistik eller store konfigurationer der, gør derfor alle sider lidt tungere, og data bliver ofte liggende, efter pluginnet er slettet. Denne forespørgsel viser de største:
SELECT option_name, ROUND(LENGTH(option_value) / 1024) AS kb
FROM wp_options
WHERE autoload IN ('yes', 'on', 'auto-on', 'auto')
ORDER BY LENGTH(option_value) DESC
LIMIT 20;Navnet afslører som regel, hvilket plugin rækken tilhører. Hører den til et plugin, du ikke bruger mere, kan den slettes. Ellers kan du slå automatisk indlæsning fra for den, men kun hvis du ved, at pluginnet selv henter den, når det skal bruge den.
Oprydning: det, der vokser af sig selv
| Hvad | Hvor det ligger | Sådan holder du det nede |
|---|---|---|
| Revisioner af indlæg og sider | wp_posts og wp_postmeta | Begræns dem i wp-config.php med define( 'WP_POST_REVISIONS', 5 ); og slet de gamle med et oprydningsplugin |
| Udløbne transients | wp_options, når der ikke er en object cache | wp transient delete --expired med WP-CLI eller et oprydningsplugin |
| Spam og kommentarer i papirkurven | wp_comments og wp_commentmeta | Tøm dem, og luk kommentarerne, hvis du ikke bruger dem |
| Afviklede baggrundsjob fra WooCommerce | wp_actionscheduler_actions og _logs | Gamle job slettes efter 30 dage som standard; tjek, at det sker, hvis tabellerne er store |
| Data fra slettede plugins | Egne tabeller, wp_options og wp_postmeta | Find dem ud fra tabel- og nøglenavne, og slet dem efter en backup |
Tag en backup, før du sletter noget direkte i databasen. OPTIMIZE TABLE kan give plads tilbage efter en stor oprydning, men på InnoDB-tabeller bygger den hele tabellen om, så kør den uden for travle tidspunkter og kun efter en oprydning, ikke som fast rutine.
Object cache: færre forespørgsler, ikke hurtigere
En persistent object cache med Redis eller Memcached gemmer resultaterne af forespørgsler og beregninger mellem requests, så det samme ikke skal hentes igen og igen. For en webshop, hvor kurv og checkout ikke kan sidecaches, tager den en stor del af presset af databasen. Men den gør ikke en langsom forespørgsel hurtigere; den første besøgende betaler stadig den fulde pris, og forespørgsler, der afhænger af den enkelte kunde, bliver sjældent genbrugt. Ret de tunge forespørgsler først, og læg cachen ovenpå.
Serveren
Den vigtigste indstilling på en MySQL- eller MariaDB-server til WordPress er innodb_buffer_pool_size: den hukommelse, databasen holder data og indekser i. Kan de data, der bruges ofte, ligge i hukommelsen, skal databasen sjældent læse fra disken. Gamle guides anbefaler at skrue op for query_cache_size, men forespørgselscachen findes ikke længere i MySQL 8, og i MariaDB er den slået fra som standard. Afstanden betyder også noget: ligger databasen på en anden server end PHP, lægges netværkstiden til hver eneste forespørgsel. På managed hosting styrer udbyderen det meste af det, så spørg, hvad der er sat op.
Ofte stillede spørgsmål
Hvor ofte skal jeg rydde op i databasen?
Revisioner og transients kan holdes nede af sig selv med de rigtige indstillinger. Ud over det er et kig på tabelstørrelser og autoload et par gange om året nok for de fleste sider, og efter du har fjernet et plugin.
Kan jeg ødelægge noget?
Ja. En forkert DELETE eller et slettet option, som et plugin stadig bruger, kan tage siden ned. Tag altid en backup, og test på en kopi, før du retter direkte i databasen.
Hjælper det at skifte til MariaDB eller en nyere MySQL?
En nyere version kan være lidt hurtigere og bedre til at planlægge forespørgsler, men den redder ikke en forespørgsel, der læser hele wp_postmeta. Ret forespørgslen, og opdater versionen, når hostingen tilbyder det.
Næste skridt
Databasen er den ene halvdel af serverens svartid. Den anden er koden, der kører, og den gennemgår vi i guiden om PHP-siden af performance. Står du med en butik, hvor filtre, admin eller checkout er blevet langsomme, kan du også få hjælp til en langsom WooCommerce-database hos os.