sql >> Databáze >  >> RDS >> PostgreSQL

PostgreSQL:Proč tento dotaz nepoužívá můj index?

Jak jste si již uvědomili, problém souvisí s použitím jiných operátorů než se rovná. Index lze nejúčinněji použít pouze pro sloupce zcela vlevo, které jsou porovnávány s hodnotou rovná se (plus jedna podmínka rozsahu).

Ve vašem příkladu:

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

Může použít index pouze pro a a b efektivně. To znamená, že DB načte všechny řádky odpovídající a a b podmínku a poté porovná každý řádek se zbývajícími podmínkami.

Když změníte filtr na c rovná se, načte (potenciálně) méně řádků (pouze ty, které odpovídají a a b a c ) a poté tyto (méně) řádky porovná s d filtr. Použití indexu je v tomto případě efektivnější.

Obecně platí, že plánovač dotazů PostgreSQL vyhodnocuje obě možnosti:(1) pomocí indexu; (2) provedení SeqScan. U obou počítá nákladovou hodnotu – čím vyšší je, tím horší je očekávaný výkon. V důsledku toho bere ten s nižší nákladovou hodnotou. Takto se rozhodne, zda index použije nebo ne, neexistuje žádný pevný práh.

Nakonec je výše napsáno "plus jedna podmínka rozsahu". To znamená, že může nejen používat index nejúčinnějším způsobem, pokud používáte rovnítko, ale také pro jednu podmínku rozsahu.

Vzhledem k tomu, že ve svém dotazu máte jednu podmínku rozsahu, navrhuji změnit index takto:

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

Nyní může používat filtry na a a b a d efektivně s indexem a potřebuje odfiltrovat pouze řádky, kde c!=5 . Ačkoli tento index lze pro váš dotaz použít efektivněji než váš původní, neznamená to automaticky, že jej PG použije. Záleží na odhadu nákladů. Ale zkuste to.

A konečně, pokud to není dostatečně rychlé a hodnotu 5 který používáte ve výrazu c!=5 je konstantní, můžete zvážit částečný index:

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

Můžete to udělat i se všemi ostatními sloupci, pokud jsou hodnoty, se kterými je porovnáváte, konstanty.

Reference:



  1. Návratová hodnota Oracle.DataAccess spustit bez dotazu (uložený proces)

  2. SQL – Najděte všechny doby výpadku a délky výpadků z dat MySQL (sada řádků s časovými razítky a stavovými zprávami)

  3. Mysql spojovací dotaz pro více značek (vztah mnoho k mnoha), který odpovídá VŠEM značkám?

  4. Sekvence hibernace nextVal vyřešena, ale není použita (Oracle)