Baza WordPressa miała prawie 5 GB. Po uporządkowaniu zajmowała 190 MB. Serwis istniał od dziesięciu miesięcy.
Działał normalnie. Klient nie zgłaszał problemów. Aktualizacje przebiegały bez błędów. Rozmiar bazy wyszedł podczas rutynowego przeglądu w ramach opieki nad stroną — przy porównaniu z drugim serwisem tego samego typu, z ponad pięciokrotnie większą liczbą publikacji, który mieścił się w 216 MB.
To nie był jeszcze problem. To był sygnał, że pod spodem dzieje się coś, czego panel WordPressa nie pokazuje. Po diagnozie okazało się, że danych w tabeli wpisów było 144 MB, a 4,4 GB stanowiła zarezerwowana, ale niewykorzystywana przestrzeń.
Poniżej trzy liczby, które doprowadziły do przyczyny, mechanizm powstawania problemu i kolejność naprawy. W takiej właśnie kolejności sprawdzamy bazy podczas opieki nad serwisami.
Sama wielkość bazy niczego nie mówi
Pięć gigabajtów nie jest jeszcze problemem. Problemem jest brak proporcji. Jeżeli niewielki serwis firmowy zajmuje kilkanaście razy więcej miejsca niż portal z setkami artykułów, warto sprawdzić, co właściwie rośnie — bo zwykle okazuje się, że przyrasta coś innego niż treść.
Panel hostingu tu nie pomoże, bo pokazuje wyłącznie sumę. Dopiero tabela systemowa information_schema odpowiada na pytanie, ile miejsca zajmują dane, ile indeksy i ile przestrzeni została już zwolniona, ale nadal pozostaje zarezerwowana.
Trzy liczby, które powiedziały więcej niż cały panel WordPressa
Pierwsze zapytanie pokazało skalę. Tabela wp_posts zawierała około 144 MB danych i jednocześnie 4,4 GB wolnej przestrzeni. To oznaczało, że baza nie zawiera pięciu gigabajtów informacji — pięć gigabajtów miał jedynie plik na dysku.
Naturalna hipoteza nasuwała się sama. Może przez lata wykonywano importy, może jakaś integracja wstawiała i usuwała rekordy, może jedna z wtyczek pracowała w pętli. Brzmiało rozsądnie.
Okazało się całkowicie błędne.
Drugie sprawdzenie dotyczyło licznika AUTO_INCREMENT. Przez cały okres istnienia tabeli przeszło przez nią nieco ponad trzy tysiące rekordów — za mało o kilka rzędów wielkości, żeby wytłumaczyć bazę liczącą kilka gigabajtów. Nawet gdyby usunięto wszystkie, dałoby to najwyżej kilkaset megabajtów wolnej przestrzeni, nie kilka gigabajtów.
I to było najważniejsze odkrycie całej diagnozy — nie dlatego, że wskazało przyczynę, ale dlatego, że przesunęło pytanie z „co tu wstawiano i kasowano" na „co tu nadpisywano". Gdybyśmy zatrzymali się na pierwszej hipotezie, kolejne godziny poszłyby na analizowanie importów, synchronizacji i logów, a problem leżał zupełnie gdzie indziej.
Właściwy kierunek potwierdziła trzecia liczba: średnia długość pojedynczego wiersza wynosiła około 137 KB. To kilkadziesiąt razy więcej niż w typowej instalacji WordPressa.
Po sprawdzeniu zawartości tabeli wszystko stało się jasne. Kreator wizualny zapisywał pełny układ strony wraz z osadzonymi stylami bezpośrednio w treści wpisu. Do tego automatyczny zapis wykonywany co minutę i brak ograniczenia liczby rewizji. Efekt: spośród 1091 rekordów aż 746 miało typ revision — około 68% wierszy w tabeli. Dwa zastrzeżenia do tej liczby, oba istotne. Po pierwsze, to udział w liczbie wierszy, a nie w zajmowanym miejscu; te dwie rzeczy potrafią się mocno rozjeżdżać i właśnie o tym jest cały ten tekst. Po drugie, WordPress oznacza autozapisy tym samym typem co rewizje, więc same te 746 rekordów jeszcze nie rozstrzyga, który z dwóch mechanizmów odpowiada za rozmiar.
Skąd wzięło się 4,4 GB pustej przestrzeni
Rewizje tłumaczą rozmiar samych danych: 1091 rekordów po około 137 KB to mniej więcej 150 MB. Nie tłumaczą jednak wolnej przestrzeni, bo tej było trzydzieści razy więcej niż wszystkich danych razem wziętych.
Odpowiedź kryje się w tym, jak działa automatyczny zapis. W analizowanej konfiguracji WordPress nie tworzył nowego rekordu przy każdym autozapisie — dla danego wpisu utrzymywał jeden rekord roboczy i aktualizował go w kółko. Licznik AUTO_INCREMENT przy takiej operacji nie drgnie, co dokładnie zgadza się z tym, co pokazało drugie zapytanie.
Warto to zastrzec, bo WordPress ma dwa osobne mechanizmy — autozapis i rewizje — i zachowują się one różnie w zależności od edytora, kreatora i konfiguracji. U siebie rozdzielisz je drugim zapytaniem z końca tekstu, zamiast zakładać, że jest tak samo.
Znaczenie ma to, co InnoDB robi z takim UPDATE-em. Bardzo duże pola tekstowe nie mieszczą się na zwykłej stronie danych, więc silnik przechowuje je na dodatkowych stronach (tzw. overflow). Aktualizacja takiego pola nie nadpisuje ich w miejscu — alokuje nowe strony, a poprzednie oznacza jako wolne. Każdy autozapis rozbudowanej strony to zatem kilkadziesiąt–kilkaset kilobajtów przestrzeni zwolnionej, ale wciąż zarezerwowanej w pliku.
Rząd wielkości się zgadza: 4,4 GB podzielone przez 137 KB daje około trzydziestu czterech tysięcy zapisów, czyli przy jednym na minutę jakieś pięćset sześćdziesiąt godzin w edytorze. Rozłożone na dziesięć miesięcy istnienia serwisu wychodzi kilkanaście godzin tygodniowo — czyli dokładnie tyle, ile zajmuje budowanie i dopracowywanie strony w kreatorze wizualnym. To jednak wyłącznie szacunek ilustrujący skalę, a nie wyliczenie; faktycznych zapisów było zapewne wyraźnie mniej, bo silnik alokuje miejsce całymi obszarami, a część przestrzeni przepada na fragmentacji, więc jeden zapis potrafi kosztować więcej niż sam rozmiar wiersza.
Licznik rekordów przez cały ten czas prawie się nie zmieniał — i właśnie dlatego panel WordPressa nie miał szans tego pokazać.
Nie potrzeba milionów rekordów ani nawet wielu wpisów. Wystarczy kilkaset bardzo dużych wierszy i zapis wykonywany co minutę. Panel nadal pokaże kilkadziesiąt stron, a plik bazy urośnie wielokrotnie — w tym przypadku w niecały rok.
Dlaczego baza nie zmniejsza się po usunięciu danych
To moment, który zaskakuje najczęściej. Po usunięciu rewizji rozmiar bazy nie zmienia się — i nie dlatego, że dane nadal istnieją.
Mechanizm jest ten sam, co opisany wyżej. Kiedy rekord zostaje usunięty, miejsce jest oznaczane jako wolne, ale plik bazy pozostaje tej samej wielkości. Właśnie to pokazuje parametr data_free. Można więc usunąć kilka gigabajtów danych i nadal widzieć niemal identyczny rozmiar bazy w panelu hostingu. Dopiero przebudowa tabeli przepisuje ją od nowa i oddaje tę przestrzeń systemowi plików.
Naprawa ma swoją kolejność
Tutaj łatwo popełnić błąd. Najpierw ogranicza się przyczynę, dopiero później usuwa skutki — odwrotnie miejsce zostałoby odzyskane i utracone ponownie w ciągu kilku tygodni.
Przyczyna miała dwa człony: bardzo duże wiersze i bardzo częsty zapis. Osobno żaden z nich nie robi problemu. Dopiero razem dają tę skalę, więc ograniczyć trzeba było oba.
- Wydłużenie interwału automatycznego zapisu z jednej minuty do pięciu — pięciokrotnie mniej aktualizacji rekordu roboczego.
- Ograniczenie liczby przechowywanych rewizji do trzech.
- Usunięcie rewizji wraz z powiązanymi metadanymi — w tej kolejności, bo odwrotna zostawia osierocone rekordy, których nie ma już po czym odnaleźć.
- Przebudowa tabeli InnoDB.
Kroki 1 i 2 ograniczają częstotliwość zapisu, krok 3 usuwa nagromadzone skutki, a dopiero krok 4 fizycznie zmniejsza plik bazy. Efekt końcowy: 5 GB → 190 MB, odzyskane około 4,8 GB. Te 190 MB to rozmiar całej bazy po przebudowie — dane, indeksy i pozostałe tabele razem; wcześniejsze 144 MB dotyczyło wyłącznie danych w tabeli wpisów.
Drugiego członu przyczyny ta lista jednak nie rusza, a to on decyduje o skali. Dlatego najważniejsze zalecenie brzmiało inaczej: przenieść style z treści wpisów do ustawień motywu i wspólnych arkuszy CSS, a w treści zostawić strukturę odwołującą się do klas. Tam, gdzie było to możliwe, zostało to zrobione. To jedyna zmiana działająca na źródło — dopóki każda strona nosi w sobie własny arkusz stylów, wiersze pozostaną gigantyczne, a wydłużony interwał autozapisu tylko rozciągnie ten sam problem w czasie.
Dlaczego to miało znaczenie
Nie dlatego, że zabrakło miejsca na dysku. Cztery gigabajty pustej przestrzeni same w sobie nie spowalniają zapytań. Największe konsekwencje były mniej oczywiste.
Pamięć podręczna bazy danych. Na hostingach współdzielonych pamięć przeznaczona dla InnoDB jest ograniczona, typowo do kilkuset megabajtów. Rozbudowana tabela wypiera z niej pozostałe dane, przez co częściej trzeba odczytywać informacje z dysku. Użytkownicy odczuwają to jako wolniejszy panel administracyjny.
Kopie zapasowe. Backup pięciogigabajtowej bazy trwa znacznie dłużej niż backup bazy liczącej dwieście megabajtów. To wydłuża czas odtwarzania po awarii i zwiększa ryzyko nieudanych kopii po przekroczeniu limitów hostingu — zwykle bez ostrzeżenia.
Koszt utrzymania. W wielu pakietach hostingowych rozmiar bazy wpływa na limity usługi. W tym przypadku serwis zbliżał się do konieczności przejścia na wyższy pakiet, mimo że rzeczywistych danych było niewiele.
Jak sprawdzić własną bazę
Zanim cokolwiek uruchomisz. Wykonaj pełną kopię bazy i upewnij się, że da się ją odtworzyć. Przebudowa tabeli InnoDB przepisuje ją w całości i przy większych bazach może chwilowo blokować zapis. Sprawdź też prefiks tabel — nie w każdej instalacji jest to
wp_. I pamiętaj, że usunięcie rewizji samymDELETEna tabeli wpisów zostawia osierocone metadane, których później nie ma już po czym odnaleźć.
Pierwsze zapytanie pokazuje rozmiar danych, wolną przestrzeń i średnią wielkość rekordów.
sql
SELECT
table_name,
ROUND(data_length/1024/1024, 1) AS dane_mb,
ROUND(data_free/1024/1024, 1) AS wolne_mb,
ROUND(avg_row_length/1024, 1) AS sredni_wiersz_kb,
table_rows,
auto_increment
FROM information_schema.tables
WHERE table_schema = DATABASE()
ORDER BY (data_length + index_length) DESC;
Najważniejsze pola:
| Kolumna | Co oznacza |
|---|---|
wolne_mb | miejsce możliwe do odzyskania po przebudowie tabeli |
sredni_wiersz_kb | średnia wielkość pojedynczego rekordu |
auto_increment | liczba rekordów, które historycznie przeszły przez tabelę |
Jedno zastrzeżenie: w InnoDB table_rows jest wartością szacunkową, a avg_row_length wylicza się z niej, więc dziedziczy ten sam błąd — potrafi odbiegać od rzeczywistości nawet o kilkadziesiąt procent. Do oceny rzędu wielkości to w zupełności wystarcza, do precyzyjnych wyliczeń nie. Dokładną liczbę wierszy daje SELECT COUNT(*).
Orientacyjnie: średnia długość rekordu powyżej 20 KB to sygnał, żeby sprawdzić przyczynę, a powyżej 50 KB zwykle oznacza już konkretny problem. Jeżeli wolne_mb przekracza rozmiar samych danych, przebudowa tabeli przyniesie zauważalny efekt.
Drugie zapytanie pokazuje strukturę tabeli wpisów — i to nie tylko w liczbie rekordów, ale też w zajmowanym miejscu. Autozapisy wydzielone są osobno, bo WordPress oznacza je w polu post_name.
sql
SELECT
CASE WHEN post_name LIKE '%-autosave-%' THEN 'autosave' ELSE post_type END AS rodzaj,
COUNT(*) AS ile,
ROUND(SUM(LENGTH(post_content))/1024/1024, 1) AS mb
FROM wp_posts
GROUP BY rodzaj
ORDER BY mb DESC;
Kolumna mb liczy samą treść wpisów, bez indeksów i narzutu silnika, więc nie zsumuje się do rozmiaru tabeli — pokazuje proporcje, nie rozmiar na dysku. Czytaj ją razem z ile, bo zwykle mówią co innego. Jeżeli revision albo autosavezajmują połowę miejsca lub więcej, sprawdź konfigurację rewizji i automatycznego zapisu. Duża liczba autozapisów przy niewielkim ich udziale w megabajtach oznacza z kolei, że rekord roboczy jest nadpisywany w kółko — czyli dokładnie ten mechanizm, który opisaliśmy wyżej, i którego nie widać po samej liczbie wierszy.
To pierwszy tekst z serii
Ten przypadek nie jest wyłącznie historią o WordPressie. Pokazuje coś szerszego: rozmiar danych bardzo często nie odpowiada temu, ile danych naprawdę istnieje. Tak samo wygląda to w strukturze strony, w katalogach produktów i w danych Schema.
Dlatego wszystkie części serii będą dotyczyły czterech warstw, w tej samej kolejności, w jakiej je sprawdzamy:
- Baza danych — co siedzi w tabelach i ile z tego jest treścią. (ten tekst)
- Struktura strony — co widzi crawler, a czego nie widzi.
- Dane produktowe — spójność katalogu, feeda i tego, co jest na stronie.
- Schema — czy maszyny mają skąd wziąć fakty o firmie.
Każda z nich potrafi przez długi czas sprawiać wrażenie, że wszystko działa poprawnie. Aż do momentu, kiedy ktoś zajrzy głębiej.
Właśnie po to jest opieka nad stroną
To nie był przypadek znaleziony podczas awarii.
Nie było błędów. Nie było zgłoszenia od klienta. Nie było komunikatu w WordPressie. Problem wyszedł podczas rutynowego przeglądu — bo takich rzeczy nie pokazuje kokpit administracyjny i nie widać ich w Google Analytics ani w Google Search Konsole.
Warto też zwrócić uwagę na tempo. Serwis miał dziesięć miesięcy. Nie chodziło o zaniedbanie ciągnące się latami, tylko o mechanizm, który przy tej konfiguracji narasta od pierwszego dnia i w rok potrafi urosnąć do kilku gigabajtów. Dlatego pierwszy przegląd bazy warto zrobić na nowym serwisie, a nie na starym.
Dlatego opieka nad stroną nie kończy się na aktualizacji wtyczek. Regularnie sprawdzamy również kondycję bazy danych, strukturę serwisu, spójność danych i elementy techniczne, które przez miesiące potrafią rosnąć niezauważenie.
Jeżeli po uruchomieniu pierwszego zapytania zobaczysz liczby, które budzą wątpliwości, a nie chcesz wykonywać takich operacji samodzielnie — skontaktuj się z nami. Tego typu przeglądy wykonujemy zarówno w ramach stałej opieki nad stronami WordPress, jak i jednorazowo.
FAQ
Skąd bierze się wolna przestrzeń, skoro nic nie było usuwane? Z aktualizacji. Przy dużych polach tekstowych każdy UPDATE alokuje nowe strony danych i zwalnia poprzednie. Zwolnione miejsce wraca do puli tabeli i bywa ponownie wykorzystane, ale przy tak dużych polach dzieje się to nieefektywnie, więc plik systematycznie rośnie. Przy autozapisie co minutę to główne źródło narastania — i takie, którego nie widać po liczbie rekordów.
Czy rewizje wpisów trzeba usuwać? Nie zawsze. W typowej instalacji zajmują niewiele i bywają przydatne. Problem pojawia się wtedy, gdy pojedynczy wiersz jest bardzo duży — wówczas każda rewizja kosztuje kilkadziesiąt razy więcej niż normalnie. W opisanym przypadku rewizje odpowiadały jednak tylko za rozmiar danych, a nie za cztery gigabajty wolnej przestrzeni.
Czy duża baza danych spowalnia stronę WordPress? Pusta przestrzeń w pliku sama w sobie nie. Spowalnia dopiero to, że rozbudowana tabela wypiera inne dane z pamięci podręcznej silnika bazy, przez co zapytania częściej trafiają na dysk.
Ile rewizji warto zostawić? Trzy do pięciu wystarcza w większości serwisów. Ustawia się to stałą WP_POST_REVISIONS w pliku konfiguracyjnym. Całkowitego wyłączenia nie polecamy, bo odbiera możliwość cofnięcia błędnej edycji.
Dlaczego baza nie zmniejszyła się po usunięciu rewizji? Ponieważ InnoDB nie oddaje miejsca systemowi plików samoczynnie. Po usunięciu danych trzeba przebudować tabelę — inaczej przestrzeń pozostaje zarezerwowana i widoczna jako data_free.
Czy wystarczy ograniczyć rewizje i wydłużyć autozapis? To spowalnia narastanie, ale nie usuwa przyczyny. Dopóki pojedynczy wiersz waży ponad sto kilobajtów, każdy zapis nadal kosztuje wielokrotnie więcej niż powinien. Trwałym rozwiązaniem jest przeniesienie stylów z treści wpisów do arkuszy motywu.
Czy dotyczy to tylko WordPressa z kreatorem wizualnym? Mechanizm jest ogólny: duże wiersze plus częste zapisy. Kreatory wizualne są najczęstszą przyczyną, bo zapisują układ i style w treści wpisu, ale to samo potrafią zrobić rozbudowane pola własne albo wtyczki logujące do tabeli wpisów.

