Som du redan insett är problemet relaterat till att använda andra operatorer än lika. Ett index kan endast användas mest effektivt för kolumnerna längst till vänster som jämförs med lika (plus ett intervallvillkor).
I ditt exempel:
create index i on t (a,b,c,d);
where a=1 and b=11 and c!=5 and d<8;
Den kan endast använda indexet för a
och b
effektivt. Det betyder att DB hämtar alla rader som matchar a
och b
villkor och kontrollerar sedan varje rad mot de återstående villkoren.
När du ändrar filtret på c
till lika, hämtar den (potentiellt) färre rader (endast de som matchar a
och b
och c
) och kontrollerar sedan dessa (färre) rader mot d
filtrera. Att använda indexet är mer effektivt i det här fallet.
I allmänhet utvärderar PostgreSQL-frågeplaneraren båda alternativen:(1) med hjälp av indexet; (2) gör en SeqScan. För båda beräknar den ett kostnadsvärde - ju högre det är desto sämre är den förväntade prestandan. Följaktligen tar den den med det lägre kostnadsvärdet. Det är så den bestämmer sig för att använda indexet eller inte, det finns ingen fast tröskel.
Slutligen skrevs "plus ett intervallvillkor" ovan. Det betyder att den inte bara kan använda indexet på det mest effektiva sättet om du använder likhetstecken, utan också för ett enskilt intervallvillkor.
Med tanke på att du har ett enda intervallvillkor i din fråga, skulle jag föreslå att du ändrar indexet så här:
create index i on t (a,b,d,c);
Nu kan den använda filtren på a
och b
och d
effektivt med indexet och behöver bara filtrera bort raderna där c!=5
. Även om detta index kan användas mer effektivt för din fråga som din ursprungliga, betyder det inte automatiskt att PG kommer att använda det. Det beror på kostnadsuppskattningarna. Men ge det ett försök.
Slutligen, om detta inte är tillräckligt snabbt och värdet 5
du använder i uttrycket c!=5
är konstant, kan du överväga ett partiellt index:
create index i on t (a,b,d)
where c!=5;
Du kan göra det med alla andra kolumner också, om värdena du jämför dem mot är konstanter.
Referenser: