Indeksy w MySQL – jak przyspieszyć zapytania w sklepie internetowym. Kompletny poradnik 2026
###02Diagnoza z terminala
Wolne zapytania SQL to najczęstsza przyczyna spadku wydajności sklepów internetowych. Gdy katalog produktów przekracza kilka tysięcy rekordów, a ruch rośnie, brak odpowiednich indeksów w MySQL może wydłużyć ładowanie strony z ułamka sekundy do kilkunastu sekund. W tym poradniku pokażę Ci, jak działają indeksy, jak je prawidłowo dobierać i jak uniknąć najczęstszych błędów, które zamiast pomóc — szkodzą.
Konfigurujesz Redis dla swojego sklepu? Sprawdź nasz poradnik: Redis w e-commerce – Rozdzielenie Cache od Sesji (Multi-Instance).
Dlaczego indeksy w MySQL są kluczowe dla e-commerce?
Wyobraź sobie księgarnię z setkami tysięcy książek. Bez katalogu (indeksu) musiałbyś przejrzeć każdą półkę, by znaleźć jeden tytuł. Tak samo działa MySQL — bez indeksu wykonuje full table scan, czyli przegląda wiersz po wierszu całą tabelę. Przy 100 tysiącach produktów to katastrofa wydajnościowa.
Jak indeks przyspiesza zapytanie?
Indeks w MySQL działa podobnie jak skorowidz na końcu książki. Zamiast czytać całą tabelę, baza danych sięga do struktury indeksu (najczęściej B-tree), odnajduje odpowiednie wskaźniki i pobiera tylko pasujące wiersze.
Przykład: Zapytanie SELECT * FROM products WHERE sku = 'PROD-12345' bez indeksu przeszukuje 500 000 wierszy. Z indeksem na kolumnie sku — odczytuje tylko 1 wiersz. Różnica w czasie wykonania? Z 4,2 sekundy do 0,001 sekundy.
Rodzaje indeksów w MySQL – który wybrać dla sklepu?
1. PRIMARY KEY (klucz główny)
Każda tabela powinna mieć klucz główny. W tabeli products to zwykle kolumna id z autoinkrementacją. MySQL automatycznie tworzy na niej unikalny indeks klastrowy, który fizycznie porządkuje dane na dysku.
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
sku VARCHAR(50) NOT NULL,
name VARCHAR(255) NOT NULL
);
2. UNIQUE INDEX (indeks unikalny)
Stosuj dla kolumn, które muszą być unikalne w całej tabeli — np. sku, ean, slug. Indeks unikalny przyspiesza wyszukiwanie i jednocześnie wymusza integralność danych.
ALTER TABLE products ADD UNIQUE INDEX idx_sku (sku);
3. INDEX (zwykły indeks, nieunikalny)
Używaj dla kolumn często występujących w klauzulach WHERE, JOIN i ORDER BY — np. category_id, manufacturer_id, status.
ALTER TABLE products ADD INDEX idx_category_status (category_id, status);
4. FULLTEXT INDEX (indeks pełnotekstowy)
Niezastąpiony przy wyszukiwarkach sklepowych. Pozwala na szybkie przeszukiwanie kolumn tekstowych (name, description) pod kątem słów kluczowych.
ALTER TABLE products ADD FULLTEXT INDEX ft_name_desc (name, description);
Zapytanie wykorzystujące indeks pełnotekstowy:
SELECT * FROM products
WHERE MATCH(name, description) AGAINST('czerwona sukienka' IN BOOLEAN MODE);
5. COMPOSITE INDEX (indeks złożony, wielokolumnowy)
To najpotężniejsze narzędzie optymalizacji. Indeks złożony obejmuje kilka kolumn i przyspiesza zapytania filtrujące po wielu warunkach jednocześnie.
ALTER TABLE orders ADD INDEX idx_customer_date (customer_id, order_date);
⚠️ Uwaga: Kolejność kolumn w indeksie złożonym ma znaczenie. Indeks
(A, B)przyspieszy zapytanieWHERE A = 1 AND B = 2orazWHERE A = 1, ale nie pomoże przyWHERE B = 2bez warunku na A. To tzw. zasada lewego prefiksu.
Jak dobrać indeksy w sklepie internetowym? Praktyczne przykłady
Przykład 1: Filtrowanie produktów po kategorii i cenie
Klient wchodzi na stronę kategorii i sortuje produkty od najtańszych. Twoje zapytanie wygląda tak:
SELECT * FROM products
WHERE category_id = 15 AND status = 'active'
ORDER BY price ASC
LIMIT 24;
Bez indeksu MySQL przeskanuje całą tabelę, nawet 200 000 wierszy. Z indeksem:
ALTER TABLE products ADD INDEX idx_cat_status_price (category_id, status, price);
Baza od razu trafia w interesujący ją zakres i pomija resztę. Czas wykonania spada z ~3,8 s do ~0,02 s.
Przykład 2: Wyszukiwarka sklepowa
Klient wpisuje „buty zimowe męskie”. Domyślne LIKE '%buty%' nie użyje indeksu i wykona full table scan. Rozwiązaniem jest FULLTEXT INDEX:
ALTER TABLE products ADD FULLTEXT INDEX ft_search (name, description, short_description);
SELECT * FROM products
WHERE MATCH(name, description, short_description)
AGAINST('+buty +zimowe +męskie' IN BOOLEAN MODE)
AND status = 'active'
LIMIT 24;
Wynik: z 8 sekund do 0,05 sekundy przy 500 000 produktów.
Przykład 3: Historia zamówień klienta
Klient loguje się i chce zobaczyć swoje zamówienia z ostatnich 30 dni:
SELECT * FROM orders
WHERE customer_id = 2847
AND order_date >= '2026-05-24'
ORDER BY order_date DESC;
Indeks złożony rozwiązuje problem:
ALTER TABLE orders ADD INDEX idx_customer_date (customer_id, order_date);
Najczęstsze błędy przy tworzeniu indeksów
Błąd 1: Indeks na każdej kolumnie
Nadmiar indeksów spowalnia operacje INSERT, UPDATE i DELETE, bo MySQL musi aktualizować każdy indeks przy każdej modyfikacji danych. W sklepie z 50 000 produktów i indeksami na 15 kolumnach, aktualizacja ceny jednego produktu może dotykać 10 struktur indeksowych.
Zasada: Twórz indeks tylko dla kolumn realnie używanych w zapytaniach.
Błąd 2: Ignorowanie zasady lewego prefiksu
-- BŁĄD: Indeks (status, price) nie pomoże przy filtrowaniu tylko po price
ALTER TABLE products ADD INDEX idx_status_price (status, price);
-- DOBRZE: Jeśli filtrujesz często po samej cenie, indeks musi zaczynać się od price
ALTER TABLE products ADD INDEX idx_price (price);
Błąd 3: Indeksowanie kolumn z niską selektywnością
Kolumny typu status (tylko 2-3 wartości: active/inactive), is_deleted (0/1) czy gender (M/F) mają niską kardynalność. Indeks na takiej kolumnie często jest ignorowany przez optymalizator MySQL, bo szybciej jest przeskanować całą tabelę niż używać indeksu zwracającego 50% wierszy.
Zasada: Indeksuj kolumny, gdzie pojedyncza wartość nie przekracza ~5-10% wszystkich wierszy.
Błąd 4: Zapominanie o EXPLAIN
Nigdy nie zgaduj — zawsze sprawdzaj plan wykonania zapytania:
EXPLAIN SELECT * FROM products WHERE category_id = 15 AND status = 'active';
Kluczowe kolumny w wyniku EXPLAIN:
- type:
ALL= full table scan (źle),reflubrange= używa indeksu (dobrze),const= idealnie - key: nazwa użytego indeksu (
NULL= brak indeksu) - rows: szacowana liczba przeszukiwanych wierszy (im mniej, tym lepiej)
- Extra:
Using filesort= MySQL sortuje ręcznie (źle),Using index= korzysta tylko z indeksu (idealnie)
Jak monitorować wydajność indeksów na produkcji?
1. Włącz Slow Query Log
Rejestruje zapytania trwające dłużej niż określony próg:
SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 1; -- w sekundach
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
2. Analizuj logi narzędziem pt-query-digest (Percona Toolkit)
pt-query-digest /var/log/mysql/slow.log
Raport pokazuje zapytania posegregowane od najbardziej obciążających — od razu widzisz, które wymagają indeksu.
3. Sprawdzaj nieużywane indeksy
Od wersji MySQL 5.6 możesz sprawdzić, które indeksy nie były używane od restartu serwera:
SELECT * FROM sys.schema_unused_indexes;
Niepotrzebne indeksy usuń komendą:
ALTER TABLE products DROP INDEX idx_niepotrzebny;
Optymalizacja indeksów dla konkretnych platform e-commerce
WooCommerce (WordPress)
Najczęściej używane tabele i rekomendowane indeksy:
-- Przyspieszenie wyszukiwarki produktów
ALTER TABLE wp_postmeta ADD INDEX idx_meta_key_value (meta_key(50), meta_value(100));
-- Filtrowanie produktów po atrybutach
ALTER TABLE wp_woocommerce_order_items ADD INDEX idx_order_product (order_id, order_item_type);
PrestaShop
-- Optymalizacja listy produktów w kategorii
ALTER TABLE ps_product_shop ADD INDEX idx_cat_active_price (id_category_default, active, price);
-- Przyspieszenie wyszukiwarki
ALTER TABLE ps_product_lang ADD FULLTEXT INDEX ft_name (name);
Magento 2
Magento intensywnie korzysta z EAV (Entity-Attribute-Value), co generuje wiele JOIN-ów. Kluczowe indeksy:
-- Indeks dla cen produktów
ALTER TABLE catalog_product_index_price
ADD INDEX idx_price_customer_group (price, customer_group_id, website_id);
Powiązany artykuł: Redis w e-commerce – Rozdzielenie Cache od Sesji. Cache i indeksy działają najlepiej, gdy są skonfigurowane razem.
FAQ — Najczęściej zadawane pytania o indeksy MySQL
Czy indeksy spowalniają zapis do bazy?
Tak. Każdy indeks musi być aktualizowany przy INSERT, UPDATE i DELETE. Przy tabeli z 10 indeksami, jeden UPDATE może wywołać 11 operacji dyskowych (1 na dane + 10 na indeksy). Dlatego indeksuj tylko kolumny, które realnie tego potrzebują.
Ile indeksów to za dużo?
W praktyce e-commerce: 5-8 indeksów na tabelę produktów to rozsądny limit. Tabela zamówień: 4-6. Wszystko zależy od specyfiki zapytań — zawsze decyduj na podstawie EXPLAIN i Slow Query Log, nie na wyczucie.
Jak sprawdzić, czy moje zapytanie używa indeksu?
EXPLAIN SELECT * FROM products WHERE sku = 'TEST-123';
Jeśli kolumna key w wyniku pokazuje nazwę indeksu (np. idx_sku) — indeks jest używany. Jeśli widzisz NULL — zapytanie wykonuje full table scan.
Czy indeks na VARCHAR(255) różni się od indeksu na INT?
Tak. Indeks na INT jest szybszy, zajmuje mniej miejsca w pamięci i na dysku. Dla kolumn VARCHAR rozważ indeks prefiksowy, np. INDEX idx_name (name(50)) — indeksuje tylko pierwsze 50 znaków, co wystarcza przy wyszukiwaniu.
Czy indeks przyspieszy ORDER BY?
Tak, pod warunkiem że kolumna z ORDER BY jest objęta indeksem (samodzielnie lub jako część indeksu złożonego) i kolejność sortowania zgadza się z kolejnością w indeksie. W przeciwnym razie zobaczysz Using filesort w EXPLAIN — czyli MySQL sortuje ręcznie, poza indeksem.
Checklista optymalizacji indeksów dla sklepu internetowego
- Włącz Slow Query Log z progiem 0,5–1 sekundy
- Uruchom pt-query-digest i znajdź 5 najwolniejszych zapytań
- Dla każdego zapytania wykonaj EXPLAIN i zidentyfikuj full table scany
- Dodaj indeksy na kolumnach z WHERE, JOIN i ORDER BY
- Sprawdź EXPLAIN ponownie — upewnij się, że MySQL używa nowych indeksów
- Usuń nieużywane indeksy (sys.schema_unused_indexes)
- Monitoruj przez tydzień — sprawdź, czy czasy zapytań się skróciły
- Powtarzaj proces co kwartał — dane i zapytania zmieniają się wraz z rozwojem sklepu
Podsumowanie: Indeksy MySQL to fundament wydajnego e-commerce
Poprawnie zaprojektowane indeksy potrafią skrócić czas zapytań z kilku sekund do milisekund. W sklepie internetowym, gdzie każda sekunda opóźnienia zmniejsza współczynnik konwersji o 7% (dane Google), to nie kwestia estetyki — to bezpośredni wpływ na przychód.
Pamiętaj o trzech złotych zasadach:
- ✅ Indeksuj to, czego szukasz — kolumny w WHERE, JOIN, ORDER BY
- ✅ Nie indeksuj wszystkiego — nadmiar spowalnia zapis
- ✅ Zawsze sprawdzaj EXPLAIN — nie ufaj intuicji, ufaj danym
Wdróż powyższą checklistę w swoim sklepie, a zobaczysz różnicę w czasie ładowania stron jeszcze tego samego dnia.
Masz pytania o optymalizację MySQL? Zostaw komentarz poniżej. Potrzebujesz pomocy z konkretnym zapytaniem? Wklej swój EXPLAIN w komentarzu — pomogę Ci go zinterpretować.
Pobierz darmową checklistę: 10 kroków do szybszego sklepu internetowego →