Hlavní navigace

Vlákno názorů k článku Zákys jménem flattening od Tomas - Flatening velmi oceňuji jako optimalizační techniku. Chtěl bych se...

  • Článek je starý, nové názory již nelze přidávat.
  • 9. 3. 2007 18:28

    Tomas (neregistrovaný)

    Flatening velmi oceňuji jako optimalizační techniku. Chtěl bych se zeptat zda PostgreSQL umí i něco jako deflattenig. Například:

    select neco
    from A
    join B on substring(A.a from 2 for 2) = substring(B.b from 3 for 2)
    

    a po úpravě optimizerem by bylo vyhodnoceno jako

    select neco
    from ( select A.*, substring(A.a from 2 for 2) as join_key from A ) as AA
    join ( select B.*, substring(B.a from 3 for 2) as join_key from B ) as BB
    on AA.join_key = BB.join_key
    

    První přístup vyprodukuje product join (nested loops), druhý by měl skončit u materializace subselectů a hash joinu. Pokud jsou tabulky A a B velké, pak druhý přístup by měl vést ke zrychlení několika řádů.

    Lze nějak sbírat vícesloupcové statistiky (statistiky přes více sloupců než jeden)? V manuálu jsem to nenašel.

    Předem díky za případné odpovědi.

    Tomáš

  • 9. 3. 2007 19:09

    Pavel Stěhule
    > Flatening velmi oceňuji jako optimalizační techniku. Chtěl bych se zeptat zda PostgreSQL umí i něco jako deflattenig. Například: ...

    Toto a dalsi divociny jedine rucne. Na to aby se pouzil hash join stejne musite mit dost pameti na hashovaci tabulky. Mozna to bude fungovat, ale predpokladam, ze pro extremni tabulky se hash join nepouzije. Tohle bych spis resil docasnym funkcionalnim indexem.

    > Lze nějak sbírat vícesloupcové statistiky (statistiky přes více sloupců než jeden)? V manuálu jsem to nenašel.

    Nelze. Pracuje se pouze s korelaci mezi sloupci.
  • 9. 3. 2007 21:19

    Marek Jakub (neregistrovaný)
    Hash join je v tomto případě velice efektivní i v případě velkých tabulek. V mém případě jsem použil 2 tabulky o cca 800000 záznamů a dotaz trval pouze 145s

    SQL> select count(*) from aa
    2 ;

    COUNT(*)
    ----------
    834471

    SQL> select count(*) from bb;

    COUNT(*)
    ----------
    834768

    SQL> select count(*) from aa, bb where substr(aa.OBJECT_NAME,2,3) = substr(bb.OBJECT_NAME, 3,3);

    COUNT(*)
    ----------
    444161718

    Přičemž provedeno bylo pouze 5346 diskových operací spojených se čtením tabulek a 7397read a 4350write operací spojených s hashováním a výsledek měl 400mio záznamů. Obě tabulky zabírají cca 2700 bloků o 8k. Test jsem prováděl na mém nb AMD Turion 64 1.6Ghz a 1G paměti, ale pro DB bylo definováno cca 270Mb.

    Rows Row Source Operation
    ------- ---------------------------------------------------
    1 SORT AGGREGATE (cr=5346 pr=7397 pw=4350 time=145033645 us)
    444161718 HASH JOIN (cr=5346 pr=7397 pw=4350 time=891859549 us)
    834768 TABLE ACCESS FULL BB (cr=2674 pr=1885 pw=0 time=1686868 us)
    834471 TABLE ACCESS FULL AA (cr=2672 pr=1162 pw=0 time=1669039 us)
  • 9. 3. 2007 20:25

    Marek Jakub (neregistrovaný)
    Máte skutečně ověřeno, že Váš případ skutečně bude skutečně vyhodnocen nested loopem? Protože prakticky se nijak neliší od joinu dvou tabulek, podle neindexovaných atributů.

    Sice neznám pg, ale v ORACLU jsem si jist, že pokud nepoužijete funkcionální indexy, tak tento případ bude téměř jistě vyhodnocen hash joinem. Testoval jsem to na tabulkách různých velikostí a nested loop jsem nodostal ani náhodou.

    Proto se mi nechce moc věřit, že by optimizer pg tento podle mého názoru vcelku primitivní případ řešil nested loopem.

    Materializace je v tomto případě neefektivní, protože pokud ty tabulky jsou velké a vy říkáte, že ano, tak dočasně vytváří v podstatě kopii obou tabulek, přičemž mu nic nebrání provádět hash join podle umělých atributů vypočtených za chodu.

    Nicméně, pokud máte ověřeno, že to skutečně provádí nested loopem, pořád nevěřím. Můžete tuto chybu snadno vyřešit právě pomocí flatteningu konstrukcí

    select neco from ( select A.*, substring(A.a from 2 for 2) as join_key from A OFFSET 0 ) as AA join ( select B.*, substring(B.a from 3 for 2) as join_key from B OFFSET 0) as BB on AA.join_key = BB.join_key
  • 9. 3. 2007 21:50

    Pavel Stěhule
    Neni nic snazsiho nez si to vyzkouset. Alespon v mem pripade se pouzil MergeJoin a prepis na subselecty byl neefektivni. Nicmene moje data byla absolutne nahodna. Verim, ze zalezi na charakteru dat.