Indeksowanie stanu częściowego indeksu w Postgres
Próbuję zrozumieć, w jaki sposób częściowe indeksy Postgres są przechowywane w Postgres. Załóżmy, że utworzę taki indeks
CREATE INDEX orders_unbilled_index ON orders (order_nr)
WHERE billed is not true
w celu szybkiego uruchomienia zapytania, takiego jak
SELECT *
FROM orders
WHERE billed is not true AND order_nr > 1000000
Postgres oczywiście przechowuje indeks order_nroparty na podzbiorze orderstabeli, zgodnie z definicją wyrażenia warunkowego billed is not true. Mam jednak kilka pytań związanych z tym:
- Czy Postgres przechowuje inny indeks wewnętrznie,
billed is not trueaby szybko znaleźć wiersze powiązane z częściowym indeksem? - Jeśli tak nie jest (1), czy spowodowałoby to przyspieszenie powyższego zapytania, gdybym utworzył oddzielny indeks na
billed is not true? (zakładając dużą tabelę i kilka wierszy zbilled is true)
EDYCJA: Moje przykładowe zapytanie oparte na dokumentacji nie jest najlepsze ze względu na to, że indeksy logiczne są rzadko używane , ale proszę rozważyć moje pytania w kontekście dowolnego wyrażenia warunkowego.
Odpowiedzi
Indeks b-drzewa można traktować jako uporządkowaną listę pozycji indeksu, z których każdy zawiera wskaźnik do wiersza w tabeli.
W indeksie częściowym lista jest po prostu mniejsza: istnieją tylko wpisy indeksu dla wierszy, które spełniają warunek.
Jeśli w WHEREklauzuli znajduje się warunek indeksu , PostgreSQL wie, że może użyć indeksu i nie musi sprawdzać warunku indeksu, ponieważ zostanie spełniony automatycznie.
Więc:
Nie, każdy wiersz znaleziony za pośrednictwem indeksu automatycznie spełni warunek indeksu, więc użycie indeksu wystarczy, aby upewnić się, że jest on spełniony.
Nie, indeks w kolumnie logicznej nie będzie używany, ponieważ nie byłby tańszy niż ten indeks częściowy, a indeks częściowy może być również użyty do sprawdzenia warunku
order_nr.W rzeczywistości jest odwrotnie: indeks częściowy może być z powodzeniem używany do zapytań, które mają tylko
booleankolumnę wWHEREwarunku, jeśli jest wystarczająco mało wierszy, które spełniają warunek.
Rozumiem, że Postgres po prostu zbuduje indeks, który będzie mógł być używany tylko do wyszukiwania rekordów, które billednie są prawdziwe. Oznacza to, że wynikowe B-drzewo byłoby indeksowane przez order_nr, ale łączyłoby się z oryginalną tabelą tylko wtedy, gdy billedbyłaby fałszywa.
Jeśli będziesz dalej czytać dokumentację , zaraz po tym, co zacytowałeś, jako przykład znajdziesz następujące zapytanie:
SELECT * FROM orders WHERE billed is not true AND amount > 5000.00;
Jest tak, że Postgres może nawet zdecydować się na użycie indeksu, który zdefiniowałeś w powyższym zapytaniu. Może użyć Twojego indeksu, aby spełnić to zapytanie, skanując cały indeks. Jeśli istnieje stosunkowo niewielka liczba zamówień, które nie zostały jeszcze zafakturowane, skanowanie indeksu order_nrnadal może być lepsze niż wykonanie pełnego skanowania tabeli.
Tak więc odpowiedź na twoje pytanie nr 1 brzmi: nie, nie ma oddzielnego indeksu dla billed, ale raczej indeks włączony order_nrmoże być używany tylko dla rekordów, dla których billedustawiono wartość fałsz. W przypadku # 2 tak, można użyć drugiego indeksu na, billed is not truezakładając, że kilka rekordów nie jest rozliczonych. Jednak nawet Twój aktualny indeks może być używany w takiej postaci, w jakiej jest.