Som du allerede har indset, er problemet relateret til at bruge andre operatorer end ligeværdige. Et indeks kan kun bruges mest effektivt for kolonnerne længst til venstre, der sammenlignes med lig (plus en områdebetingelse).
I dit eksempel:
create index i on t (a,b,c,d);
where a=1 and b=11 and c!=5 and d<8;
Den kan kun bruge indekset til a
og b
effektivt. Det betyder, at databasen henter alle rækker, der matcher a
og b
tilstand og kontrollerer derefter hver række mod de resterende betingelser.
Når du ændrer filteret på c
til lig, henter den (potentielt) færre rækker (kun dem, der matcher a
og b
og c
) og kontrollerer derefter disse (færre) rækker mod d
filter. Brug af indekset er mere effektivt i dette tilfælde.
Generelt evaluerer PostgreSQL-forespørgselsplanlæggeren begge muligheder:(1) ved hjælp af indekset; (2) laver en SeqScan. For begge beregner den en omkostningsværdi - jo højere den er, jo dårligere er den forventede ydeevne. Følgelig tager den den med den mindre omkostningsværdi. Det er sådan, den beslutter sig for at bruge indekset eller ej, der er ingen fast tærskel.
Endelig er der skrevet "plus en række betingelse" ovenfor. Det betyder, at den ikke kun kan bruge indekset på den mest effektive måde, hvis du bruger lighedstegn, men også for en enkelt områdebetingelse.
I betragtning af at du har én enkelt områdebetingelse i din forespørgsel, vil jeg foreslå at ændre indekset sådan her:
create index i on t (a,b,d,c);
Nu kan den bruge filtrene på a
og b
og d
effektivt med indekset og behøver kun at filtrere rækkerne væk, hvor c!=5
. Selvom dette indeks kan bruges mere effektivt til din forespørgsel som din oprindelige, betyder det ikke automatisk, at PG vil bruge det. Det afhænger af omkostningsestimaterne. Men prøv det.
Endelig, hvis dette ikke er hurtigt nok og værdien 5
du bruger i udtrykket c!=5
er konstant, kan du overveje et delvist indeks:
create index i on t (a,b,d)
where c!=5;
Du kan også gøre det med alle andre kolonner, hvis de værdier, du sammenligner dem med, er konstanter.
Referencer: