Jak już zauważyłeś, problem jest związany z używaniem operatorów innych niż równe. Indeks może być używany najefektywniej tylko w przypadku skrajnych lewej kolumny, które są porównywane z wartościami równymi (plus jeden warunek zakresu).
W twoim przykładzie:
create index i on t (a,b,c,d);
where a=1 and b=11 and c!=5 and d<8;
Może używać indeksu tylko dla a
i b
wydajnie. Oznacza to, że baza danych pobiera wszystkie wiersze pasujące do a
i b
warunku, a następnie sprawdza każdy wiersz pod kątem pozostałych warunków.
Kiedy zmienisz filtr na c
równa się, pobiera (potencjalnie) mniej wierszy (tylko te pasujące do a
i b
i c
), a następnie porównuje te (mniej) wiersze z d
filtr. W tym przypadku użycie indeksu jest bardziej efektywne.
Ogólnie rzecz biorąc, planer zapytań PostgreSQL ocenia obie opcje:(1) używając indeksu; (2) wykonanie SeqScan. W obu przypadkach oblicza wartość kosztów — im wyższy, tym gorsza jest oczekiwana wydajność. W konsekwencji bierze ten o mniejszej wartości kosztowej. W ten sposób decyduje się użyć indeksu, czy nie, nie ma ustalonego progu.
Na koniec napisano "plus jeden warunek zakresu" powyżej. Oznacza to, że może nie tylko używać indeksu w najbardziej efektywny sposób, jeśli używasz znaków równości, ale także dla pojedynczego warunku zakresu.
Biorąc pod uwagę, że w zapytaniu występuje jeden warunek dotyczący zakresu, sugeruję zmianę indeksu w następujący sposób:
create index i on t (a,b,d,c);
Teraz może używać filtrów na a
i b
i d
wydajnie z indeksem i wystarczy odfiltrować wiersze, gdzie c!=5
. Chociaż ten indeks może być użyty w zapytaniu bardziej efektywnie niż oryginalny, nie oznacza to automatycznie, że PG go użyje. To zależy od kosztorysów. Ale spróbuj.
Wreszcie, jeśli to nie wystarczy, i wartość 5
używasz w wyrażeniu c!=5
jest stała, możesz rozważyć indeks częściowy:
create index i on t (a,b,d)
where c!=5;
Możesz to zrobić również ze wszystkimi innymi kolumnami, jeśli wartości, z którymi je porównujesz, są stałymi.
Referencje: