tl;dr Musisz dodać indeks do item_id
. „Czarną magię” indeksowania Postgres opisano w 11. Indeksy
.
Masz indeks złożony na (topic_id, item_id)
i kolejność kolumn jest ważna. Postgres może użyć tego do indeksowania zapytań na topic_id
, zapytania dotyczące obu topic_id
i item_id
, ale nie (lub mniej wydajnie) item_id
sam.
Od 11.3. Indeksy wielokolumnowe ...
-- indexed
select *
from topics_items
where topic_id = ?
-- also indexed
select *
from topics_items
where topic_id = ?
and item_id = ?
-- probably not indexed
select *
from topics_items
where item_id = ?
Dzieje się tak, ponieważ indeks złożony, taki jak (topic_id, item_id)
przechowuje najpierw identyfikator tematu, a następnie identyfikatory produktów, które również mają ten identyfikator tematu. Aby skutecznie wyszukać identyfikator elementu w tym indeksie, Postgres musi najpierw zawęzić wyszukiwanie do identyfikatora tematu.
Postgres może odwrócić indeks, jeśli uważa, że jest to warte wysiłku. Jeśli istnieje niewielka liczba możliwych identyfikatorów tematów i duża liczba możliwych identyfikatorów indeksu, wyszuka identyfikator indeksu w każdym identyfikatorze tematu.
Załóżmy na przykład, że masz 10 możliwych identyfikatorów tematów i 1000 możliwych identyfikatorów produktów oraz indeks (topic_id, index_id)
. To tak, jakby mieć 10 wyraźnie oznaczonych pojemników na identyfikatory tematów, każdy z 1000 wyraźnie oznaczonych pojemników na identyfikatory produktów w środku. Aby uzyskać dostęp do zasobników identyfikatorów produktów, należy zajrzeć do każdego zasobnika identyfikatorów tematu. Aby użyć tego indeksu na where item_id = 23
Postgres musi przeszukać każdy z 10 zasobników z identyfikatorami tematów pod kątem wszystkich zasobników o identyfikatorze 23.
Ale jeśli masz 1000 możliwych identyfikatorów tematów i 10 możliwych identyfikatorów produktów, Postgres musiałby przeszukać 1000 grup identyfikatorów tematów. Najprawdopodobniej zamiast tego wykona pełne skanowanie tabeli. W takim przypadku chciałbyś odwrócić swój indeks i uczynić go (item_id, topic_id)
.
Zależy to w dużej mierze od dobrych statystyk stołowych, co oznacza upewnienie się, że autovacuum działa prawidłowo.
Możesz więc uciec z jednym indeksem dla dwóch kolumn, jeśli jedna kolumna ma znacznie mniejszą zmienność niż inna.
Postgres może również używać wielu indeksów, jeśli uważa, że spowoduje to uruchomienie zapytania szybciej
. Na przykład, jeśli masz indeks na topic_id
i indeks na item_id
, może użyj obu indeksów i połącz wyniki. Na przykład where topic_id = 23 or item_id = 42
może użyć indeksu topic_id, aby wyszukać temat o identyfikatorze 23, a indeksu item_id, aby wyszukać element o identyfikatorze 42, a następnie połączyć wyniki.
Jest to generalnie wolniejsze niż posiadanie złożonego (topic_id, item_id)
indeks. Może to być również wolniejsze niż użycie jednego indeksu, więc nie zdziw się, jeśli Postgres zdecyduje się nie używać wielu indeksów.
Ogólnie rzecz biorąc, dla indeksów b-drzewa, gdy masz dwie kolumny, masz trzy możliwe kombinacje.
- a + b
- a
- b
I potrzebujesz dwóch indeksów.
- (a, b) -- a i a + b
- (b) -- b
(a, b)
obejmuje oba wyszukiwania a i a + b. (b)
obejmuje wyszukiwanie b
.
Gdy masz trzy kolumny, masz siedem możliwych kombinacji.
- a + b + c
- a + b
- a + c
- a
- b + c
- b
- c
Ale potrzebujesz tylko trzech indeksów.
- (a, b, c) -- a, a + b, a + b + c
- (b, c) -- b, b + c
- (c, a) -- c, c + a
Jednak prawdopodobnie chcesz uniknąć indeksowania trzech kolumn. Często wolniej . To, czego naprawdę chcesz, to to.
- (a, b)
- (b, c)
- (c, a)
Czytanie z indeksu jest wolniejsze niż czytanie z tabeli. Chcesz, aby indeksy zmniejszały liczbę wierszy, które muszą zostać odczytane, ale nie chcesz, aby Postgres musiał wykonywać więcej skanowania indeksów niż to konieczne.