MySQL slow query log — znajdowanie i optymalizacja wolnych zapytań SQL
Opublikowano: 9 kwietnia 2026 · Kategoria: Bazy danych
WordPress ładuje się 5 sekund, a MySQL zjada 80% CPU serwera? Najprawdopodobniej winne są wolne zapytania SQL bez indeksów — pełne table scany na setkach tysięcy wierszy. MySQL slow query log to wbudowane narzędzie diagnostyczne, które rejestruje dokładnie te zapytania. Dowiedz się jak je znaleźć i naprawić.
Włączenie slow query log
Dodaj do /etc/mysql/mysql.conf.d/mysqld.cnf (Ubuntu) lub
/etc/my.cnf (CentOS):
[mysqld] # Włącz slow query log slow_query_log = 1 slow_query_log_file = /var/log/mysql/mysql-slow.log # Próg w sekundach (1s to dobry punkt startowy) long_query_time = 1 # Loguj też zapytania bez indeksów (przydatne dla diagnostyki) log_queries_not_using_indexes = 1 # Ogranicz logi "no index" do 200/min (żeby nie zapchać logu) log_throttle_queries_not_using_indexes = 200
# Restart MySQL sudo systemctl restart mysql # Lub włącz dynamicznie (bez restartu) — efekt do następnego restartu mysql -u root -p -e "SET GLOBAL slow_query_log = ON;" mysql -u root -p -e "SET GLOBAL long_query_time = 1;" mysql -u root -p -e "SET GLOBAL log_queries_not_using_indexes = ON;" # Sprawdź aktualne ustawienia mysql -u root -p -e "SHOW VARIABLES LIKE 'slow%';" mysql -u root -p -e "SHOW VARIABLES LIKE 'long_query_time';"
Analiza — mysqldumpslow
mysqldumpslow jest dołączony do MySQL. Agreguje podobne zapytania i sortuje wyniki:
# 10 najwolniejszych zapytań (sort by query time) mysqldumpslow -s t -t 10 /var/log/mysql/mysql-slow.log # 10 najczęstszych wolnych zapytań mysqldumpslow -s c -t 10 /var/log/mysql/mysql-slow.log # Zapytania zawierające "wp_posts" mysqldumpslow -g "wp_posts" /var/log/mysql/mysql-slow.log # Przykładowy output: # Count: 423 Time=2.15s (910s) Lock=0.00s (0s) Rows=1000.0 (423000) # SELECT * FROM wp_posts WHERE post_status='S' AND post_type='S'
Analiza — pt-query-digest (Percona Toolkit)
Percona Toolkit to potężniejsze narzędzie — grupuje zapytania, pokazuje percentyle i procentowy udział w łącznym czasie:
# Instalacja sudo apt install percona-toolkit # Ubuntu/Debian # Analiza slow logu pt-query-digest /var/log/mysql/mysql-slow.log | head -100 # Output zawiera: # Rank Response time Calls R/Call V/M Item # 1 245.3123 42.0% 1823 0.1346 0.16 SELECT wp_posts wp_postmeta # ... # Detailed view: pełne zapytanie + statystyki czasu
EXPLAIN — diagnostyka planu wykonania
Po znalezieniu problematycznego zapytania, użyj EXPLAIN żeby zrozumieć dlaczego jest
wolne:
EXPLAIN SELECT * FROM wp_posts WHERE post_status = 'publish' AND post_type = 'post' ORDER BY post_date DESC LIMIT 10; -- Wynik: tabela z kolumnami: -- id | select_type | table | type | possible_keys | key | rows | Extra -- 1 | SIMPLE | wp_posts | ALL | NULL | NULL | 84523 | Using where; Using filesort
| type | Znaczenie | Ocena |
|---|---|---|
system / const | Zapytanie o 1 wiersz przez PK lub UNIQUE | Doskonałe |
eq_ref | JOIN przez unikalny indeks, 1 wiersz na match | Bardzo dobry |
ref | Użycie indeksu (nieunikalnego) | Dobry |
range | Skanowanie zakresu przez indeks (BETWEEN, ) | Akceptowalny |
index | Pełny skan indeksu (lepsza niż ALL) | Słaby |
ALL | Pełny table scan — każdy wiersz sprawdzany | Krytyczny |
Dodawanie indeksów
-- Problem: brak indeksu na (post_status, post_type) -- Rozwiązanie: composite index ALTER TABLE wp_posts ADD INDEX idx_status_type_date (post_status, post_type, post_date); -- Sprawdź istniejące indeksy SHOW INDEX FROM wp_posts; -- Weryfikacja po dodaniu indeksu (EXPLAIN powinien teraz pokazać ref) EXPLAIN SELECT * FROM wp_posts WHERE post_status = 'publish' AND post_type = 'post' ORDER BY post_date DESC LIMIT 10;
Uwaga: Na współdzielonym hostingu (cPanel/DirectAdmin) zazwyczaj masz uprawnienia do tworzenia indeksów przez phpMyAdmin. Na VPS możesz robić to bezpośrednio w MySQL CLI.
Optymalizacja WordPress — typowe problemy
- wp_options autoload — zapytanie
SELECT * FROM wp_options WHERE autoload='yes'ładuje wszystkie opcje przy każdym żądaniu. Sprawdź:SELECT COUNT(*), SUM(LENGTH(option_value)) FROM wp_options WHERE autoload='yes'. Jeśli powyżej 1 MB — wyczyść nieużywane opcje wtyczek. - wp_postmeta bez indeksu — zapytania przez
meta_keyczęsto nie używają indeksu. Wtyczka Query Monitor (WordPress) pokaże wolne zapytania w panelu admina. - Brak limitu w WP_Query —
posts_per_page=-1ładuje WSZYSTKIE posty. Zawsze ustawiaj limit. - JOIN na dużych tabelach — tabele wp_posts + wp_postmeta mogą mieć miliony wierszy. Użyj WP Object Cache (Redis/Memcached) żeby cache'ować wyniki.