Optymalizacja silnika relacyjnej bazy danych (MariaDB / MySQL) to jedno z najważniejszych zadań w życiu administratora serwera. Wielu z nich ucieka od tego tematu, polegając na konfiguracji domyślnej, dopóki strona nie zacznie generować błędów „Connection timed out”. Tymczasem odpowiednie dostrojenie bazy do dostępnego sprzętu – takiego jak np. Raspberry Pi 5 wyposażone w 8 GB RAM i dysk NVMe – potrafi dwukrotnie zwiększyć liczbę obsługiwanych zapytań na sekundę (QPS) przy jednoczesnym obniżeniu czasu odpowiedzi serwera (TTFB).
Pamiętaj jednak o złotej zasadzie: w bazach danych nie ma nic za darmo. Skrócenie czasu zapytania zazwyczaj odbywa się kosztem większego zużycia pamięci RAM, a przyspieszenie operacji zapisu (Insert/Update) często oznacza drobny kompromis w kwestii bezpieczeństwa danych podczas nagłej przerwy w dostawie prądu.
Diagnoza: Jak sprawdzić, co poprawić?
Nie optymalizuj bazy „w ciemno”. Narzędziem, od którego zaczyna każdy administrator, jest skrypt MySQLTuner. Pobiera on na żywo statystyki z pracującego silnika i wskazuje wąskie gardła.
Ważne: Zanim uruchomisz tuner, upewnij się, że serwer bazy danych działał pod normalnym obciążeniem (z normalnym ruchem użytkowników) przez co najmniej 24 godziny. Włączenie go zaraz po restarcie bazy da fałszywe, często abstrakcyjne wyniki.
Pobranie i uruchomienie skryptu:
wget http://mysqltuner.pl/ -O mysqltuner.pl
wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/vulnerabilities.csv -O vulnerabilities.csv
wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/basic_passwords.txt -O basic_passwords.txt
perl mysqltuner.pl --host 127.0.0.1
Konfiguracja (Plik 50-server.cnf)
Wszystkie poniższe wartości ustawiamy w pliku konfiguracyjnym serwera (najczęściej /etc/mysql/mariadb.conf.d/50-server.cnf lub /etc/mysql/my.cnf) pod nagłówkiem [mysqld].
Poniższe wartości zostały dobrane dla sprzętu klasy Raspberry Pi 5 (8 GB RAM / NVMe) i serwisu o umiarkowanym/dużym natężeniu ruchu.
Połączenia i „odcinanie” nieaktywnych sesji
max_connections = 150 – Maksymalna liczba jednoczesnych połączeń. Wzrost tej wartości chroni przed błędem „Too many connections”, ale każde połączenie rezerwuje odrobinę RAM-u.
wait_timeout = 60 (lub nawet 30) – Domyślnie serwer czeka aż 8 godzin (28800 sekund), zanim zamknie nieaktywne połączenie od skryptu PHP. Obniżenie tej wartości do 60 sekund błyskawicznie zwalnia zasoby (RAM i gniazda).
Pamięć podręczna (Wycofane Query Cache)
W starych poradnikach znajdziesz mnóstwo dyrektyw zaczynających się od query_cache_*. Uwaga: W nowoczesnej architekturze MariaDB 11 oraz MySQL 8, Query Cache został całkowicie porzucony i usunięty z kodu. Silniki te polegają na optymalizatorach, architekturze InnoDB oraz na zewnętrznym cache’u obiektowym (jak Valkey/Redis obsługiwanym na poziomie PHP).
Skupiamy się zatem na definicjach tabel:
table_open_cache = 2000 – Liczba plików z tabelami otwartymi w pamięci. Przyspiesza dostęp, ale wymaga odpowiednio wysokiego limitu otwartych plików (tzw. ulimit w systemie operacyjnym).
table_definition_cache = 1400 – Ile definicji schematów (struktur) tabel trzymać w RAM-ie. Zmniejsza narzut na operacje I/O dysku.
Serce systemu: Optymalizacja silnika InnoDB
Dziś niemal każda nowoczesna baza (w tym WordPress) korzysta wyłącznie z silnika InnoDB. To jego konfiguracja decyduje o prędkości Twojej strony.
innodb_buffer_pool_size = 2G (lub nawet 3G/4G) – Najważniejszy parametr w całym pliku. Określa, ile pamięci RAM przypisujemy buforowi, który w locie ładuje dane i indeksy. Zasada: im więcej (do około 60-70% całkowitego RAM-u maszyny, jeśli to dedykowany serwer bazy), tym rzadziej baza musi sięgać do dysku.
innodb_log_file_size = 512M – Rozmiar dziennika transakcji (tzw. Redo Log). Duży rozmiar potężnie przyspiesza zapis do bazy (szczególnie operacje masowe), ale w przypadku „twardego” resetu zasilania, baza będzie się dłużej odbudowywać przy ponownym rozruchu.
innodb_log_buffer_size = 32M – Zwiększa rozmiar danych „w locie”, zanim zostaną zrzucone do fizycznego pliku Redo Logu na dysku.
innodb_flush_log_at_trx_commit = 2 – Kolejny Gamechanger dla wydajności.
Wartość 1 (domyślna) daje 100% pewności zapisu kosztem powolnego działania.
Wartość 2 daje potężnego „kopa” wydajnościowego do operacji zapisu (np. przy imporcie, czy ciężkim WooCommerce). Ryzyko? Jeśli system (np. zasilanie RPi) ulegnie awarii (kernel panic / hard reset), możesz stracić do 1 sekundy transakcji. Dla większości stron WWW jest to ryzyko absolutnie akceptowalne w zamian za uzyskane przyspieszenie.
innodb_thread_concurrency = 4 – Ogranicza liczbę aktywnych wątków do fizycznej ilości rdzeni w Raspberry Pi 5. Chroni system przed tzw. Context Switching (przeciążeniem procesora wynikającym z żonglowania zbyt dużą ilością zapytań naraz).
Optymalizator MariaDB 11 a dyski NVMe / SSD
MariaDB 11 wprowadza nowy, bardzo szczegółowy model kosztów optymalizatora (optimizer_*_cost). W skrócie: silnik przed wykonaniem zapytania zgaduje, jak najszybciej odzyskać dane.
Poniższe wartości obniżają wagę „kary” dla operacji dyskowych. Dlaczego? Domyślne wagi były pisane w erze powolnych, talerzowych dysków HDD. Dziś, dysponując dyskiem NVMe, odczyt jest na tyle szybki, że chcemy zachęcić optymalizator do częstszego korzystania z tych zapytań kosztem skomplikowanych pętli w pamięci.
optimizer_disk_read_cost = 5
optimizer_disk_read_ratio = 0.01
optimizer_index_block_copy_cost = 0.01
optimizer_key_compare_cost = 0.005
optimizer_key_copy_cost = 0.01
optimizer_key_lookup_cost = 0.2
optimizer_row_copy_cost = 0.03
optimizer_row_lookup_cost = 0.1
Podsumowanie: Realne efekty
Po wdrożeniu tych kilku linijek i zrestartowaniu usługi (sudo systemctl restart mariadb), różnica w wydajności na sprzęcie typu RPi 5 czy VPS jest drastyczna.
W moim środowisku testowym czas realizacji poszczególnych zapytań spadł o ponad połowę, a przepustowość wzrosła dwukrotnie. Pamiętaj jednak: optymalizacja to proces ciągły. Aplikuj zmiany stopniowo, monitoruj zużycie RAM-u (komendą htop) i sprawdzaj logi pod kątem ewentualnych ostrzeżeń po każdym restarcie.
