sql >> Database >  >> RDS >> PostgreSQL

PostgreSQL:waarom gebruikt deze query mijn index niet?

Zoals u zich al realiseerde, heeft het probleem te maken met het gebruik van andere operatoren dan gelijken. Een index kan alleen het meest efficiënt worden gebruikt voor de meest linkse kolommen die worden vergeleken met gelijken (plus één bereikvoorwaarde).

In jouw voorbeeld:

create index i on t (a,b,c,d);
where a=1 and b=11 and c!=5 and d<8;

Het kan de index alleen gebruiken voor a en b efficiënt. Dat betekent dat de DB alle rijen ophaalt die overeenkomen met de a en b voorwaarde en vergelijkt vervolgens elke rij met de overige voorwaarden.

Wanneer u het filter wijzigt op c gelijk is aan, haalt het (potentieel) minder rijen op (alleen de rijen die overeenkomen met a en b en c ) en vergelijkt vervolgens die (minder) rijen met de d filter. Het gebruik van de index is in dit geval efficiënter.

Over het algemeen evalueert de PostgreSQL-queryplanner beide opties:(1) met behulp van de index; (2) een SeqScan doen. Voor beide berekent het een kostenwaarde - hoe hoger het is, hoe slechter de verwachte prestaties. Bijgevolg neemt het degene met de kleinere kostprijs. Dit is hoe het beslist om de index te gebruiken of niet, er is geen vaste drempel.

Ten slotte staat hierboven "plus één bereikvoorwaarde". Dat betekent dat het de index niet alleen op de meest efficiënte manier kan gebruiken als u gelijktekens gebruikt, maar ook voor één enkele bereikvoorwaarde.

Aangezien u één enkele bereikvoorwaarde in uw zoekopdracht heeft, raad ik u aan de index als volgt te wijzigen:

create index i on t (a,b,d,c);

Nu kan het de filters op a . gebruiken en b en d efficiënt met de index en hoeft alleen de rijen weg te filteren waar c!=5 . Hoewel deze index efficiënter voor uw zoekopdracht kan worden gebruikt dan uw oorspronkelijke, betekent dit niet automatisch dat PG deze zal gebruiken. Het hangt af van de kostenramingen. Maar probeer het eens.

Tot slot, als dit niet snel genoeg is en de waarde 5 u gebruikt in de uitdrukking c!=5 constant is, kunt u een gedeeltelijke index overwegen:

 create index i on t (a,b,d)
        where c!=5;

Je zou dat ook met alle andere kolommen kunnen doen, als de waarden waarmee je ze vergelijkt constanten zijn.

Referenties:



  1. Hoe stopwoorden in MYSQL te resetten?

  2. Moet de tijdzone van MySQL worden ingesteld op UTC?

  3. Laatste invoeg-ID ophalen toont verkeerd nummer

  4. Haal de database of een ander bestand op uit de interne opslag met behulp van run-as