A lassú WordPress oldal diagnózisa majdnem mindig ugyanott csúszik el. Megnézzük a PageSpeed pontszámot, cserélünk egy gyorsítótár bővítményt, bekapcsolunk egy képoptimalizálót, és remélünk. Közben a szerveren az történik, hogy egyetlen oldalletöltés kiszolgálása alatt két-hatszáz SQL lekérdezés fut le, és ezek egy része olyan adatot húz a memóriába, amit az adott oldal soha nem használ fel. Ez az írás arról szól, hogyan dönthető el mérésekkel, hogy a PHP futása vagy az adatbázis viszi az időt, és mit tehetsz akkor, ha az adatbázis.

Honnan tudod, hogy az adatbázis lassít, és nem a PHP?
A szétválasztás egyetlen összehasonlításon múlik. Vedd a szerveroldali válaszidőt (a TTFB értéket), és vedd mellé az összes SQL lekérdezés összesített futásidejét ugyanazon a kérésen. Ha az SQL összidő adja a válaszidő nagy részét, adatbázis-ügyed van. Ha a válaszidő javát a PHP futása eszi meg, akkor kódot, hook-okat és külső API-hívásokat kell vizsgálni.
Egy tipikus mérés így áll össze. A kategórialap TTFB-je 840 ms, ezen belül 412 lekérdezés fut le 590 ms összidővel. Ez adatbázis-terhelés. Egy másik oldalon a TTFB szintén 800 ms körül van, de 96 lekérdezés összesen 70 ms alatt lefut, és a maradék 700 ms a PHP-ban telik. Itt hiába optimalizálsz indexet, a nyeresége mérhetetlen lesz.
Saját tapasztalat. Nálam a gyakorlati küszöb 30 százalék körül van. Ha az SQL összidő ennél kisebb szeletet ad a válaszidőből, először a PHP oldalt bontom meg, és csak utána nyúlok az adatbázishoz. Fontos, hogy a mérést kijelentkezve és bejelentkezve is végezd el, mert az adminban gyakran két-háromszor annyi lekérdezés fut, és a két eset teljesen más javítást kér.
Melyik eszközzel látod magukat a lekérdezéseket?
A lekérdezés-figyelő bővítmény a legrövidebb út. A Query Monitor ingyenes, a WordPress.org tárolójában van, és a lekérdezéseket komponensenként csoportosítja, tehát megmutatja, melyik bővítmény vagy téma hány lekérdezést és mennyi időt visz.
Hivatalos információ. A WordPress támogat egy beépített konstanst, amellyel a lekérdezéseket a rendszer eltárolja a futás idejére. Ezt a wp-config.php fájlba írod, a sor a következő.
define( 'SAVEQUERIES', true );
Ez memóriát fogyaszt és lassít, ezért éles oldalon csak a mérés idejére kapcsold be, utána vedd ki. A Query Monitorban négy panel ad valódi információt. A Queries by Component megmondja a felelőst, a Queries by Caller megmutatja a hívó függvényt, a Duplicate Queries kilistázza a többször, azonos formában lefutó lekérdezéseket, a Slow Queries pedig a küszöb fölé érőket. A duplikált lekérdezés majdnem mindig hiányzó gyorsítótárazásra utal, nem hiányzó indexre.
Ha a probléma nem az oldalletöltésben, hanem egy háttérfolyamatban van, a WP-CLI a barátod. A wp profile stage és a wp profile hook parancsokkal szakaszonként látod a lekérdezésszámot és az SQL időt, ráadásul a mérés nem függ a böngészőtől és a hálózattól.
Hogyan kapcsolod be a lassú lekérdezések naplóját?
A lassú lekérdezések naplója azt fogja meg, amit a böngészőből indított egy-két mérés kihagy, például a hétvégi karbantartó feladatokat és a keresőrobotok kéréseit. MySQL és MariaDB alatt a bekapcsolás három beállítás.
SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 0.5; SET GLOBAL log_queries_not_using_indexes = 'ON';
A fél másodperces küszöb WordPress oldalon jó kiindulás. Ha egy nap alatt semmi nem kerül a naplóba, vidd le 0,1-re. A felgyűlt naplót ne szemmel olvasd, hanem összegezve. A mysqldumpslow -s t -t 20 slow.log a húsz legtöbb időt vivő mintát adja, a Percona Toolkit pt-query-digest eszköze pedig normalizálja a lekérdezéseket, így az ezer apró változat egy sorba kerül.
Két csapda van itt. A SET GLOBAL újraindításig él, tehát a tartós beállítás a szerver konfigurációs fájljába kerül. Megosztott tárhelyen pedig jó eséllyel nem érsz hozzá, ilyenkor a lekérdezés-figyelő bővítmény és a hoszting saját riportja marad.
Mekkora a postmeta és az options tábla, és mennyi az autoload?
A táblaméret önmagában nem hiba, de megmondja, hol keresd a bajt. Ezzel a lekérdezéssel a tíz legnagyobb táblát kapod meg.
SELECT table_name, ROUND((data_length+index_length)/1024/1024) AS mb, table_rows FROM information_schema.TABLES WHERE table_schema = DATABASE() ORDER BY (data_length+index_length) DESC LIMIT 10;
Saját tapasztalat. A wp_postmeta tábla félmillió sor fölött kezd érezhetően viselkedni, ha a szűrők meta értékekre keresnek. Az wp_options táblában ötezer sor fölött szinte biztosan van elhagyott adat. Az árva postmeta sorok számát ezzel nézd meg.
SELECT COUNT(*) FROM wp_postmeta pm LEFT JOIN wp_posts p ON p.ID = pm.post_id WHERE p.ID IS NULL;
Ezek olyan sorok, amelyek egy már törölt bejegyzéshez tartoznak, és semmilyen funkciót nem szolgálnak. Ugyanígy érdemes megszámolni a lejárt átmeneti értékeket (transient), amelyek egy nem használt bővítmény után bent ragadnak.
Miért az autoload összege a legdrágább rejtett teher?
Itt jön a saját nézőpontom. Nagy oldalakon ritkán találok egyetlen lassú lekérdezést, amire rá lehet mutatni. Amit viszont szinte mindig találok, az több ezer autoload sor az options táblában, és ez minden egyes kérésnél terhel, a főoldalon, a kosárban és a wp-cron futásakor is. Mérd meg így.
SELECT COUNT(*) AS sorok, ROUND(SUM(LENGTH(option_value))/1024) AS kb FROM wp_options WHERE autoload IN ('yes','on','auto','auto-on');
Hivatalos információ. A WordPress 6.6 átalakította az autoload kezelését, ezért a mezőben a régi yes érték mellett újabb értékek is előfordulnak, és a mag már nem tölt be automatikusan egy bizonyos méret fölötti egyedi beállítást. A Webhely állapota (Site Health) panelen külön teszt figyelmeztet, ha az autoload adatok összmérete túl nagy.
A legnagyobb tételeket ezzel szedd ki.
SELECT option_name, LENGTH(option_value) AS byte FROM wp_options WHERE autoload IN ('yes','on','auto','auto-on') ORDER BY byte DESC LIMIT 25;
A lista élén rendszerint ugyanazok a típusok állnak. Elrejtett admin figyelmeztetések naplója, licencellenőrzések válasza, egy átirányítás-kezelő teljes szabálytáblája, egy űrlapbővítmény mentett bejegyzései, és a már letörölt bővítmények bent maradt beállításai. Saját tapasztalat. Láttam 1,5 MB fölötti autoload összméretet olyan oldalon is, ahol a napi látogatószám három számjegyű volt.
A javítás óvatos lépésekben megy. Először készíts adatbázis-mentést, utána egyetlen soron állítsd át az automatikus betöltést, és mérj újra.
wp option update <option_name> --autoload=no
Törölni csak azt töröld, ami biztosan egy eltávolított bővítményhez tartozik, és a név alapján be tudod azonosítani. Szakmai feltételezés. Az objektum-gyorsítótár (Redis, Memcached) mérsékli ezt a terhet, mert az autoload sorok egy kulcsból jönnek, de a PHP oldali visszafejtés és memóriafoglalás szerintem megmarad, tehát a takarítás objektum-gyorsítótár mellett is hoz valamit.
Hogyan jutsz el a legdrágább lekérdezéstől a javításig?
- Reprodukáld a lassúságot. Írd fel a pontos URL-t, azt hogy bejelentkezve vagy anélkül mérsz, és futtasd háromszor, mert az első mérés hideg gyorsítótárral fut.
- Rögzítsd a kiindulást. TTFB medián, lekérdezésszám, SQL összidő, csúcs memóriahasználat.
- Azonosítsd a felelőst komponensenként. Ha egy bővítmény 180 lekérdezést ad egyetlen oldalon, az önmagában is elég információ.
- Futtasd le a leglassabb lekérdezésen az
EXPLAINparancsot. A type oszlop ALL értéke teljes tábla-olvasást jelez, a rows oszlop nagy száma sok átvizsgált sort, az Extra oszlopban álló Using temporary és Using filesort pedig ideiglenes munkát. - Döntsd el, milyen javítás kell. Index a szűrésre, gyorsítótár az ismétlődésre, adattisztítás a szemétre, bővítmény-csere a rosszul megírt kódra.
- Indexet csak akkor tegyél fel, ha az EXPLAIN tényleg hiányzó indexet mutat, és a lekérdezés gyakran fut. A meta értékre szűrő lekérdezéseknél egy összetett index segíthet, például
ALTER TABLE wp_postmeta ADD INDEX meta_key_value (meta_key(32), meta_value(32));formában. Mérd meg utána az írási műveleteket is, mert minden index a mentést lassítja. - Gyorsítótárnál három szint van. Tartós objektum-gyorsítótár a szerveren, saját átmeneti érték a drága számításra, és a lekérdezés szűkítése, például a
no_found_rowsparaméterrel, ha nem kell lapozás. - Mérj újra ugyanazzal a módszerrel, ugyanabban az állapotban.
Saját tapasztalat. A legtöbb tartós megoldás nem index volt, hanem adatszerkezet-váltás. Ha egy terméklista meta mezőre szűr, és abból lesz a szűrő, akkor a mező taxonómiába vagy saját táblába költöztetése hoz igazi különbséget, az index csak tolja a határt.
Mit mérj a javítás előtt és után?
A rövid válasz az, hogy pontosan ugyanazt, ugyanabban az állapotban, ugyanabból a hálózatból. Ellenőrzőlista a méréshez:
- TTFB medián tíz mérésből, külön hideg és meleg gyorsítótárral
- lekérdezésszám és SQL összidő ugyanazon az URL-en
- a leglassabb egyedi lekérdezés futásideje milliszekundumban
- az autoload sorok száma és összmérete kilobájtban
- a
wp_postmetaés azwp_optionssorszáma és tábla-mérete - a lassú lekérdezések naplójának találatszáma 24 óra alatt
- csúcs memóriahasználat és PHP hibanapló-bejegyzések
- az admin oldalak és az admin-ajax hívások válaszideje
Írd le a mérés körülményeit is, tehát a napszakot, a gyorsítótár állapotát és azt, hogy futott-e közben mentés. Ezek nélkül a második mérés nem összehasonlítható az elsővel, és könnyen elhiszed magadról a javulást, ami a napi terhelés ingadozása volt.
Mikor nem éri meg optimalizálni?
Akkor, amikor a nyereség kisebb, mint a kockázat vagy a ráfordítás. Négy ilyen helyzet gyakori.
Ha a TTFB már 200 ms körül van, és a látogató lassúságot érzékel, akkor a szűk keresztmetszet jó eséllyel a böngészőben van, tehát a képekben, a betűtípusokban és a külső szkriptekben. Ha egy lekérdezés naponta egyszer fut az adminban, a fél másodperce nem ér meg egy sémamódosítást. Ha a WordPress mag táblájára tennél fel egyedi indexet, számolj azzal, hogy egy frissítés vagy egy migráció visszaírhatja a sémát, ezért ezt írásban dokumentálni kell. Ha pedig a szerver CPU-ja folyamatosan tele van egy megosztott tárhelyen, akkor a csomag- vagy szolgáltató-váltás rövidebb út, mint hónapokig lekérdezéseket csiszolni.
Szakmai feltételezés. Egy 100 ms-ról 60 ms-ra javított válaszidőt a konverzióban szerintem nem fogsz kimutatni, egy 2,5 másodpercről 0,8 másodpercre vitt válaszidőt viszont igen. Ez a gyakorlatban azt jelenti, hogy addig érdemes menni, amíg az adatbázis már nem a legdrágább tétel, és onnan más területre vinni az energiát. Garantált eredményt egyik javítás sem ad, a mérés viszont megmutatja, hogy jó irányba mentél.
Források és további olvasnivalók
- WordPress Developer Resources, Code Reference és Common APIs
- Query Monitor bővítmény dokumentációja, WordPress.org Plugin Directory
- WordPress Site Health (Webhely állapota) fejlesztői dokumentáció
- MySQL 8.0 Reference Manual, The Slow Query Log és az EXPLAIN fejezetek
- MariaDB Knowledge Base, Slow Query Log és Optimization
- Percona Toolkit dokumentáció, pt-query-digest
- WP-CLI Command Reference, wp option és wp profile
- web.dev, Time to First Byte és Core Web Vitals
- Google Search Central, Page Experience dokumentáció
- Ha a szerveroldali válaszidő kevesebb mint harmadát teszi ki az SQL összidő, akkor a PHP-t érdemes vizsgálni, nem az adatbázist.
- A Query Monitor komponensenként megmutatja, melyik bővítmény hány lekérdezést és mennyi időt visz, ezért ezzel kezdj.
- A lassú lekérdezések naplója 0,5 másodpercre állított küszöbbel egy nap alatt kiadja a valódi problémás lekérdezéseket.
- Az autoload sorok összméretét mérd meg külön, mert az minden egyetlen kérésnél terhel, gyorsítótár mellett is.
- A javítás előtt és után ugyanazt a hat számot rögzítsd, különben nem tudod, hogy tényleg jobb lett.
Gyakori kérdések
Hány lekérdezés a sok egy WordPress oldalletöltésen?
Nincs hivatalos határ, de a gyakorlatban egy egyszerű aloldal 30 és 80 lekérdezés között kiszolgálható. Száz fölött már érdemes komponensenként megnézni, melyik bővítmény adja a többletet, kétszáz fölött pedig szinte biztosan van elhagyható lekérdezés.
Mekkora autoload méret számít soknak?
A WordPress Webhely állapota panel akkor figyelmeztet, ha az automatikusan betöltött beállítások összmérete túl nagy. Saját tapasztalatom szerint 300 KB alatt ritkán van ebből probléma, 1 MB fölött viszont érdemes átnézni a legnagyobb tételeket, mert azok minden kérésnél betöltődnek.
Megoldja a Redis vagy a Memcached a lassú adatbázist?
Sokat segít, mert az ismétlődő lekérdezések eredménye a memóriából jön. Egy rosszul megírt, szűrés nélküli lekérdezést viszont nem tüntet el, és a nagy autoload adatmennyiség PHP oldali feldolgozása is megmarad, ezért a takarítás és a gyorsítótár együtt működik jól.
Biztonságos indexet tenni a wp_postmeta táblára?
Működik, de két dolgot kell hozzá tudni. Minden új index lassítja az írást, és a WordPress mag táblájára tett egyedi index a séma későbbi frissítésénél elveszhet. Készíts mentést, dokumentáld a változást, és mérd meg az írási műveleteket is, ne csak az olvasást.
Mit tegyek, ha megosztott tárhelyen nincs hozzáférésem a lassú lekérdezések naplójához?
Ilyenkor a lekérdezés-figyelő bővítmény adja a legtöbb információt, mellette a WP-CLI profilozó parancsai és a hoszting saját erőforrás-riportja. Az options és a postmeta tábla méretét, valamint az autoload összeget phpMyAdminból is le tudod kérdezni.
Honnan tudom, hogy a javítás tényleg segített?
Csak akkor tudod, ha a javítás előtt és után ugyanazt a néhány számot rögzítetted, például a TTFB mediánt, a lekérdezésszámot, az SQL összidőt és az autoload méretet. Egyetlen mérés a napi terhelés ingadozása miatt félrevezető, ezért mérj többször, ugyanabban az állapotban.
Források és további olvasnivalók
Ezen az oldalon a hivatalosan igazolt információt elsődleges forrásokból építjük fel; a saját tapasztalatot és a szakmai becslést mindig külön jelöljük a szövegben.