Indexovani - teorie

Karel Zak zakkr na zf.jcu.cz
Středa Říjen 16 14:25:22 CEST 2002


On Wed, Oct 16, 2002 at 12:44:49PM +0200, Honza Pazdziora wrote:

> Operator OR je zcela opacna situace. Protoze to, ze mate index nad
> (sl1, sl2) Vam vyhledani vsech zaznamu, kde se sl1 = 'xxx' nijak
> neurychli. Zato ale pote, co server nasel vsechny zaznamy, kde sl1
> = 'xxx', musi (pokud nad sl2 nebude index) projit jeste jednou celou
> tabulku a zjistit, kdeze se sl2 = 'yyy'. Cili vysledkem pravdepodobne

 Todle neni uplne presne. Nerekl bych, ze musi projit jeste jednou
 celou tabulku, ale porovnani vsech polozek dane tabulky, ktere jsou 
 obsazene ve WHERE se provadi pri jednom pruchodu.

# explain SELECT * FROM ii WHERE i1='a' OR i2='b';
                                 QUERY PLAN                                 
----------------------------------------------------------------------------
 Seq Scan on ii  (cost=0.00..25.00 rows=10 width=28)
   Filter: ((i1 = 'a'::character varying) OR (i2 = 'b'::character varying))


Podobne je to pokud neexistuje spolecny index. K tabulce se pristupuje 
pomoci indexu a data v tabulce se dale filtruji podle polozek v indexu 
neobsazenych. Mam mocit, ze zde zaznelo, ze pokud jsou indexy na obe 
polozky dotazu tak je to stejne jako jejich spolecny index. To je 
pochopitelne hloupost. Pouzije se jen jeden index a na dalsi cast 
se pouzije "filtrovani" -- pokud by se pouzilo vice indexu tak by se 
pak muselo delat nejake filtrovani/merge mezi vysledky z jednotlivych indexu
(coz se deje pri pouziti napr. subselectu nebo nejakych joinu). Viz:

Neexistuje spolecny index, ale existuji samostatne indexy:

# explain SELECT * FROM ii WHERE i1='a' AND i2='b';
                            QUERY PLAN                             
-------------------------------------------------------------------
 Index Scan using i2_idx on ii  (cost=0.00..17.08 rows=1 width=28)
   Index Cond: (i2 = 'b'::character varying)
   Filter: (i1 = 'a'::character varying)


Pouziji se oba indexy a vysledek se prefiltruje:

test=# explain SELECT * FROM ii WHERE i1='a' 
               AND i2 IN (SELECT i2 FROM ii WHERE i2='b');
                                   QUERY PLAN                                    
---------------------------------------------------------------------------------
 Index Scan using i1_idx on ii  (cost=0.00..102.42 rows=2 width=28)
   Index Cond: (i1 = 'a'::character varying)
   Filter: (subplan)
   SubPlan
     ->  Materialize  (cost=17.07..17.07 rows=5 width=14)
           ->  Index Scan using i2_idx on ii  (cost=0.00..17.07 rows=5 width=14)
                 Index Cond: (i2 = 'b'::character varying)

Pouziji se oba indexy a vysledek a pak mergne:

test=# explain SELECT * FROM ii a JOIN ii b ON a.i1=b.i2;
                                  QUERY PLAN                                  
------------------------------------------------------------------------------
 Merge Join  (cost=0.00..171.50 rows=5000 width=56)
   Merge Cond: ("outer".i1 = "inner".i2)
   ->  Index Scan using i1_idx on ii a  (cost=0.00..52.00 rows=1000 width=28)
   ->  Index Scan using i2_idx on ii b  (cost=0.00..52.00 rows=1000 width=28)


> Samozrejme, pokud ty atributy budou mit vhodnou kardinalitu nebo budou
> splneny spousty jinych podminek, tak bude lepsi projit treba celou
> tabulku nez pouzivat jakekoli indexy, cili tohle berte pouze jako
> obecne doporuceni jak zacit. Konkretni situaci si budete muset
> zanalyzovat sam.

 Todle je hodne dobra pripominka (viz. index na boolean:-) . Obcas 
se lide zlobi, ze jim napr. PG ignoruje jejich skvele indexy a 
pritom jejich pouziti by bylo v danem pripade na obtiz.

    Karel

-- 
 Karel Zak  <zakkr na zf.jcu.cz>
 http://home.zf.jcu.cz/~zakkr/
 
 C, PostgreSQL, PHP, WWW, http://docs.linux.cz, http://mape.jcu.cz


Další informace o konferenci Test