Indeks B-drzewo

Najpopularniejszy typ indeksu oparty na zrównoważonym drzewie, świetny do zakresów i sortowania. Domyślny indeks w większości baz relacyjnych.

Indeks B-drzewo (B-tree index) to najpopularniejsza struktura indeksu w bazach relacyjnych — zrównoważone drzewo wyszukiwań, w którym wszystkie liście leżą na tej samej głębokości, a klucze są w nich uporządkowane rosnąco. Dzięki temu baza znajduje wiersz po wartości kolumny w czasie logarytmicznym zamiast skanować całą tabelę. To domyślny typ indeksu w PostgreSQL, MySQL (InnoDB), SQL Server, Oracle i SQLite — gdy piszesz CREATE INDEX bez podania typu, prawie zawsze dostajesz właśnie B-drzewo. W praktyce silniki używają wariantu B+drzewa, gdzie dane wskaźnikowe trzymane są wyłącznie w liściach, a liście są połączone listą — co przyspiesza odczyty zakresowe.

Jak to działa

Wyobraź sobie drzewo z korzeniem na górze i liśćmi na dole. Węzły pośrednie zawierają posortowane klucze, które mówią silnikowi „idź w lewo albo w prawo”. Schodzisz od korzenia do liścia, podejmując po drodze garść porównań — przy milionach wierszy to zwykle 3-4 odczyty strony zamiast przejścia przez całą tabelę. Drzewo samo się równoważy przy INSERT, UPDATE i DELETE (rozszczepianie i scalanie węzłów), więc głębokość pozostaje mała niezależnie od liczby rekordów.

Ponieważ klucze są uporządkowane, B-drzewo świetnie obsługuje nie tylko równość (WHERE id = 42), ale też zakresy (BETWEEN, <, >), sortowanie (ORDER BY bez osobnego kroku sortowania) i dopasowanie prefiksu (LIKE 'abc%'). To dlatego jest domyślnym wyborem do niemal wszystkiego.

Przykład z praktyki

Masz tabelę orders z milionem wierszy i zapytanie filtrujące po dacie. W PostgreSQL dorzucasz indeks:

CREATE INDEX idx_orders_created ON orders (created_at);

Teraz SELECT * FROM orders WHERE created_at >= '2026-01-01' ORDER BY created_at; trafia w indeks. Sprawdzisz to przez EXPLAIN ANALYZE — zamiast Seq Scan zobaczysz Index Scan using idx_orders_created. Dla zapytań po kilku kolumnach naraz buduje się indeks złożony, np. (user_id, created_at), ale pamiętaj o regule lewego prefiksu: taki indeks pomoże filtrować po user_id lub po obu kolumnach, ale nie po samym created_at.

Na co uważać

  • Indeks to nie magia — przy bardzo małej selektywności (kolumna typu status z trzema wartościami) optymalizator i tak woli skan sekwencyjny. To nie błąd.
  • Funkcja na kolumnie zabija indeks. WHERE LOWER(email) = '...' nie skorzysta ze zwykłego indeksu na email — potrzebujesz indeksu funkcyjnego albo przepisania zapytania.
  • Każdy indeks kosztuje. Spowalnia zapisy i zajmuje miejsce, bo musi być aktualizowany przy każdej zmianie danych. Nie indeksuj „na zapas".
  • Do wyszukiwania pełnotekstowego ani po JSON-ie B-drzewo się nie nadaje — tam sięgasz po GIN, GiST czy indeksy full-text.

Pojęcia powiązane

Warto znać też: B+drzewo, indeks złożony (composite), indeks pokrywający (covering index), indeks hash, GIN i GiST, plan zapytania i EXPLAIN, selektywność oraz klucz podstawowy, który zwykle sam tworzy indeks B-drzewo.