Vlákno názorů k článku Zákys jménem flattening od krtek - Velmi pekny clanek, sice ja delam s Oracle,...

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

    krtek (neregistrovaný)
    Velmi pekny clanek, sice ja delam s Oracle, ale rad si prectu i o jinych databazich aby byl clovek trochu v obraze.
    Nevite proc se tak brani zavedeni hintu, v oracle je to bezna vec ktera celkem dost pomaha. Normalne clovek vsechno nechava na optimalizatoru a az v pripade nejakych problematickych dotazu clovek vetsinou optimalizuje rucne a to vetsinou pomoci hintu.
  • 7. 3. 2007 14:20

    Pavel Stěhule
    Je to o filozofii. Pokud pouziji hinty aniz bych vedel o duvodech chovani databaze, tak je vetsinou pouziji spatne. Pokud znam databazi, tak zase vetsinou nepotrebuji hinty :-). PostgreSQL indexy pouziva naprosto bez problemu. Nesmi se jen zapominat na ANALYZE. Dost casto hint vede k tomu, ze optimalizujete dotaz pro jednu specifickou podmnozinu dat, a pro dalsi dotaz s hintem bude provaden neefektivne. Takze se hinty chapou jako neco, co umoznuje zacatecnikum napsat neco co je rychle a spatne, a tudiz je to zavrzenihodne. Je lepsi, kdyz si zacatecnik uvedomi, co ma za problem, pripadne se zepta a vyresi problem korektne (tj. bez pouziti hintu ;-)). A zase, vuci ostatnim o.s. databazim, PostgreSQL ma planer o dost sofistikovanejsi (coz neni vzdy vyhoda, pro jednodussi dotazy je pomalejsi nez u MySQL).
  • 7. 3. 2007 16:41

    ugra karma (neregistrovaný)
    jo chce to podporu pro uzivatelem nastavovatelne jak moc ma planer optimalizovat http://www.pdc.kth.se/doc/SP/manuals/db2-7.1/html/db2s0/frame3.htm#sqls0661

    jinak db2 je zadara pro linux i pro komercni pouziti. vubec db2 je hezka db, kdyz porovnate sql jazyk oracle a mysql, tak db2 ho ma nejlepsi, nejsou tam zadny nadstandardni zbytecnosti pro ruzne speedup hacky.

    btw proc name pgsql podporu pro release savepoint? mysql to uz umi.
  • 7. 3. 2007 19:23

    Petr (neregistrovaný)
    Chapu, co pisete, ale prijde mi to jako purismus; jako povyseni idelogie nad praktickou pouzitelnost.

    A v praktickem software, aspon ve vsech projektech, kdy jsem se pohyboval, je dulezitejsi predikovatelnost doby nejhorsiho pripadu nezli prumerny cas nebo cas nejlepsiho pripadu. A podle me zkusenosti mi tuto predikovatelnost da hint, nebot hintem stabilizuji execution plan; jinak nikdy nevyloucim, ze mi spatna statistika vytvori nekolikadenni selecty.

    Chapu, ze SQL je vymyslen jako jazyk typu "reknete mi, co vam mam dat, ne jak to mam ziskat" a ze hinty zkali tuto jeho pruzracnost.

    Ovsem z druhe strany vzato: Optimalizator se ze statistik snazi zjistit vztahy mezi daty, podstatne pro efektivni provadeni prikazu. V aplikacni domene se ale muze stat, ze mezi daty jsou dalsi vztahy, ktere ze statistiky nezjistim (jako ze statistiky datumu nezjistim, ze po pondelku vzdy nasleduje utery). Pak potrebuji zpusob, jak bud optimalizator vyradit a zoptimalizovat to sam, anebo jak optimalizatoru ten vztah vysvetlit. "Hint" a "doprogramovavani optimalizatoru" jsou pak uz jen ruzne odstiny tehoz principu, pricemz hint je jednodussi, prehlednejsi a mene riskantni.
  • 7. 3. 2007 21:28

    anonymní
    Hinty jsou proste diskutabilni tema. Osobne vsem radim, aby aplikaci pravidelne monitorovali a prubezne ladili. Jak to uz zalezi na konretnim databazovem systemu. Hintama, prepsanim dotazu, .. Pravidelne se objevuji navrhy na zavedeni hintu do pg. Zatim jeste nikdo nemel dostatek energie a nezduvodnil je dostatecne aby presvedcil Toma Lane. Primarne se v pg jde cestou co nejsofistikovanejsiho optimalizeru. Zase, jedna se o o.s. Pokud napisete patch, obhajite jej, tak se v core objevi. Ale muzete mi verit, ze to jsou obcas dost velke bitvy.
  • 8. 3. 2007 19:19

    Petr (neregistrovaný)
    Ale vzdyt cely tenhle clanek je o tom, ze v pg hinty jsou. Akorat nemaji syntaxi /*+USE_HASH(a b)*/ ale OFFSET 0.

    Prijde mi to cele takove zabavne intelektualne nepoctive :-)
  • 8. 3. 2007 13:39

    Dramenbejs (neregistrovaný)
    Problém je v tom, že když se v DB změní data, například po přesunutí aplikace na produkční server, tak vám hinty více uškodí, než pomůžou.

    Jestli chcete používat hinty, tak budete při každé změně rozložení dat přepisovat hromadu selectů v aplikaci.
  • 8. 3. 2007 21:50

    Martin Kavalec (neregistrovaný)
    Taky mi to připadá jako fundamentalismus říct, že hinty jsou špatné a basta. A v tomto světle je pak čiré farizejství, když si tam jeden hint převlečený za OFFSET nechají; když už optimalizovat, tak pořádně a OFFSET 0 by se měl vyhodnotit jako zbytečná klauzule, ne? Když to dotáhnu ad absurdum, tímto stylem by se taky mohlo zakazovat použití indexu přidáním "AND sloupec=sloupec" do klauzule WHERE.

    Ne vždycky je nutné nad tabulkou vytvářet statistiky -- např. při různých agregacích a transformacích dat pro datový sklad. Např. vím, že ve vstupní tabulce mám ke každému identifikátoru max. 3 záznamy a unikátních identifikátorů jsou tam třeba 3 miliony a tuto tabulku potřebuju sumarizovat podle těch ID. Planner to chce groupovat hashováním, protože netuší, ze těch unikátních identifikatrů je tolik. Buď mu můžu říct, ať si spočítá statistiky, anebo připsat na konec dotazu kouzelné "option (order group)", čímž mu poradím, že je rychlejší si tabulku sesortovat a pak už jet sekvenčně. (což se testováním ukázalo jako rychlejší a po vytvoření statistik na to planner přijde taky) Ale vzhledem k tomu, že tato operace je jednorázová, pak se tabulka smaže a příště se bude agregovat zase nová tabulka, je to vytváření statistik trochu drahý "hint". (ten zápis hintu je pro MS SQL, čímž taky odpovídám na dotaz někde v diskuzi, jestli MS SQL má hinty)

    Každopádně, uznávám, že je to dost specifický případ. Asi bych si hodně rozmýšlel použít hint někde v kódu aplikace, kde fakt hrozí, že sice zrovna teď mi to pomůže, ale až se změní charakter dat, tak si na tom ta aplikace vyláme zuby, kdežto se statistikama se tomu prostě přizpůsobí.

    Jinak pro zajimavost, někdy před rokem a půl jsem u Postgresu narazil na toto zajímavé chování:

    explain select neco_id from tabulka where neco_id between 100000 and 150000 order by neco_id;

    navrhoval použít seq scan tabulky (a bylo to pomalé, v tabulce bylo tusim cca 700 tis. záznamů).
    Pokud jsem to přepsal na

    select * from
    (select neco_id from tabulka where neco_id betweeen 100000 and 125000
    union all
    select neco_id from tabulka where neco_id betweeen 125001 and 150000) x
    order by neco_id

    tak uz se pouzil index scan (+ append).
    Na tom, ze hinty jsou spatne asi neco bude, protoze me to aspon prinutilo podivat se do manualu a upravit parametr random_page_cost a pak se pouzil index i v prvnim pripade. Ten analyzer vykonostnich charakteristik disku, jak nekdo v diskuzi navrhoval, asi neni spatny napad :)
  • 8. 3. 2007 22:41

    Pavel Stěhule
    > tak uz se pouzil index scan (+ append).
    > Na tom, ze hinty jsou spatne asi neco bude, protoze me to aspon prinutilo podivat se do
    > manualu a upravit parametr random_page_cost a pak se pouzil index i v prvnim pripade.
    > Ten analyzer vykonostnich charakteristik disku, jak nekdo v diskuzi navrhoval, asi neni
    > spatny napad :)

    Kdyby zalezelo jenom na rychlosti disku. Zalezi na taky na velikosti pameti a na velikosti diskove cache vcetne systemove. Random_page_cost bych se bal zmenit, zato efective_cache_size je na linuxu poddimenzovana a doporucuje se zvysit. Obecne 8.1 ma poddimenzovanou konfiguraci a chce to pouzivat hodnoty, ktere jsou v 8.2. Dost to pomuze.
  • 7. 3. 2007 20:54

    Marek Jakub (neregistrovaný)
    V zásadě platí, že hint by měl dodat optimalizátoru dodatečnou informaci, kterou ze statistik nedostane, nebo je zavádějící.

    Nepoužívám a neznám PostgreSQL, používám ORACLE, ale i tato finta může být nebezpečná a dost bolet. Jde o to, že použitím OFFSET 0 podle mého názoru dojde k materializaci poddotazu (vytvoření výsledku v temporary paměti) a pokud je výsledkem poddotazu velká množina, tak výsledek může být horší než použití suboptimálního indexu.

    To byl zřejmě případ Vašeho kolegy, který 10% dotazů zrychlil a u zbylých 90% došlo k trojnásobnému spomalení. Prostě to nejde použít pokaždé, pokud by to šlo, optimizer by to už dávno tak dělal :-)

    Jinak v ORACLE se používá stejný trik právě tehdy, kdy chcete provést materializaci poddotazu, protože není vhodné, aby optimizer použil unnesting (nevím český ekvivalent a odhnízdění mi přijde divné). Použije se rownum, což je virtuální sloupec, který počítá řádky výstupu. Pokud bych použil Váš příklad, tak ten dotaz by vypadal takto:

    select * from (select t1.*, rownum r from t1 where a = 20) s where s.b = 20

    Toto provede v podstatě totéž, čehož chcete dosáhnout Vy, tj. vyhodnotí nejdříve vnořený dotaz, a na to aplikuje filter b = 20.

    Protože tímto trikem napravujete statistiky, které neodpovídají datům, další technikou, která je použitelná v ORACLE, je modifikace statistik, ale to už je většinou černá magie a měla by být používaná ještě s větším rozmyslem, než "flattening"
  • 7. 3. 2007 21:34

    Pavel Stěhule
    ju, myslim si, ze je to naprosto presne. Modifikace statistik mne jeste nenapadla. Je videt, ze s Oraclem se dela vyssi magie nez s pg :-)
  • 7. 3. 2007 22:51

    Marek Jakub (neregistrovaný)
    Doufám, že to nevyznělo, že modifikace statistik je v ORACLE běžná praxe. Osobně jsem ji ještě nikdy nepoužil. Domnívám se, že k takovému voodoo se dospěje až při databázích v řádu stovek Gb - Tb.

    Nevím jak probíhá sběr statistik v pg, ale v ORACLE se u tak velkých tabulek obvykle skenuje pouze vzorek cca 1-5%, což stačí, pokud jsou data rovnoměrně rozložena. Pokud ale nejsou, nebo se náhodou při sběru trefíte do blbých částí, tak statistiky neodpovídají skutečnosti. Pak nastává čas pro voodoo se statistikama.

    Nebo když máte aplikace, které nevěří na NULL hodnoty (různé systémy, které jsou "multidatabázové") a tudíž místo NULL používají nějakou konstantu, např. 1.1.1900 pro datum, tak mají problém, protože matou optimizer. Ten spočívá v tom, že optimizer předpokládá, že hodnoty jsou v prostoru rovnoměrně rozdělené a přitom mezi 1.1.1900 a např. 1.1.2000 nemáte žádnou hodnotu, ale mezi 1.1.2000 do 1.1.2007 máte dejme tomu 1mio záznamů. Běžně ale děláte dotazy na konkrétní den, přičemž optimizer si myslí, že na jeden den připadá cca 25 záznamů (1m/39081), ale ve skutečnosti jich je 391 (1m/2557). Při malých datech ten rozdíl není podstatný, ale čím více dat, tím více bude v takových případech optimizer dělat chyby.

    Obdobný problém může nastat, pokud se použije např. 1.1.4000 pro nekonečno.

    Záludnost modifikace statistik je v tom, že má vliv na všechny dotazy nad danou tabulkou. A nejhorší je, že když statistiku opravíte tak, že odpovída skutečnosti (např. odstraníte vliv toho 1.1.1900), tak vám přestanou fungovat již odladěné dotazy.

    V tom mají hinty velkou výhodu, protože i když neřeší přičinu (chybné statistiky), ale mají pouze lokální vliv, takže opravujete pouze to co nefunguje.
  • 8. 3. 2007 9:08

    Pavel Stěhule
    Hmm, takový programátory bych stavěl ke zdi :-). Chápu Toma, proč si nechce zasírat kód Postgresu, něčím co se stejně používá jen pro "******" napsané aplikace. U Oraclu je to o byznysu, pg vývojářům nikdo nic neplatí.
  • 8. 3. 2007 9:51

    Marek Jakub (neregistrovaný)
    Neříkejte, že jste pro volbu co platí neomezeně nikdy nepoužil nějaký konstantní datum, třeba 1.1.4000. Pokud ano, tak si k té zdi můžete také stoupnout :-). Já už tam stojím.
  • 8. 3. 2007 10:38

    Pavel Stěhule
    Použil, dokud jsem jak trotl poslouchal starší borce, naštěstí v aplikaci, která nikdy nebyla v provozu. Ale i tak se za to stydím, a beru to jako hřích mládí :-). Pokud si nevystačím s hodnotou NULL (což se může stát), tak si přidám jeden flagovej sloupec navíc. 100x se to vyplatí. Prostě už jsem vyrostl, z toho, bych se snažil ušetřit bit. Dobře mne vyškolil Postgres. První patche, který jsem tam posílal, přepsali, tak že jsem je nepoznal. A když už si mysleli, že bych mohl dostat rozum, tak mi patch 10x omlátili o hlavu. O magických číslech kolujou úžasný historky, kvůli tomuhle nešvaru padaly rakety, letadla. Naštěstí v bezpečných aplikacích, které procházejí několikanásobným auditem už to nikoho nenapadne. Jinak bych se bál sednout do letadla.

    Viděl jsem hromadu ****** systémů, které v podstatě nelze udržovat, ook, na jednom jsem se před pár lety i podílel. Snažím se trochu myslet, by výsledek nějak vypadal. S trochou úsilí se dá dobře psát i ve VB nebo PHPku, s MySQL. Chce to mít ale na zdi velký nápis: Mysli! a nedělej blbosti. Hledat na netu, číst a snažit se nad vším přemýšlet. A nemyslet si, že jsem spolkl veškerou moudrost světa. Každá verze sw je trochu jiná, s každou se dá psát o fous slušněji, čistěji, spolehlivěji.
  • 8. 3. 2007 11:10

    Marek Jakub (neregistrovaný)
    Většinou nejde o to ušetŕit bit, i když to implemetačně je několik bajtů, o to dnes skutečně nejde. Pokud si někdo jěště hraje s místem, tak je to buď nadšenec a trochu blázen, nebo to diktují hw podmínky, pouźití v settop boxech a podobně.

    Podstatná je ale udržovatelnost sw, kde můžete narazit na to, že akademicky čisté řešení je výkonnostné nepoužitelné. Chce to rozpoznat tu hranici, kde trvat na čistotě, a kde je vhodné ustoupit. Někdy to je těžké a s odstupem času se můžete hrozit, co jste to napáchal, když šlo použít mnohem elegantnější řešení.

    Pokud se vrátím k vyjádření nekonečna konstantou, a úkol zjišťování kolize dnou časových intervalů <a,b> a <c,d>. Tak při použití konstanty pro -nekonečno a +nekonečno je vyhodnocování průniku triviální podmínkou (a <= d) and (c <= b), která se za jistých podmínek dá i indexovat a dá se s tím rozumně žít. Puristické použití Vaší metody vede k brutální podmínce, která indexovat možná nejde vůbec.

    Podle mne je řešením kompromis, kde uživatel sice zadává počátky a konce intervalů a flagem označuje, jestli se jedná o +-nekonečno (A, IS_INFTY, B, IS_INFTY), nicméně aplikační vrstva naplní ještě extra atributy, třeba X_A a X_B (které uživatel nevidí a nemá možnost změnit), kde -+ nekonečno nahradí přísl. konstantou, která je zadrátovaná pouze na tomto jednom místě. A úkol je vyřešen vcelku elegantně a čistě.

    Ale tím jen opakuji to co říkáte, že téměř vždy lze nalézt čisté řešení.
  • 8. 3. 2007 15:03

    Pavel Stěhule
    A zlepšuje se to:
    postgres=# create table x(t timestamp);
    CREATE TABLE
    postgres=# insert into x values('infinity');
    INSERT 0 1
    postgres=# select * from x;
        t     
    ----------
     infinity
    (1 row)
    
  • 8. 3. 2007 11:54

    ugra karma (neregistrovaný)
    chce to lepsi vacuum analyze. v soucasne dobe dela tohle:

    INFO: vacuuming "data"
    INFO: "data": found 0 removable, 1063474 nonremovable row versions in 9001 pages
    DETAIL: 0 dead row versions cannot be removed yet.
    There were 1034 unused item pointers.
    30 pages contain useful free space.
    0 pages are entirely empty.
    CPU 1.39s/0.97u sec elapsed 6.10 sec.
    INFO: analyzing "data"
    INFO: "data": scanned 3000 of 9001 pages, containing 354595 live rows and 0 dead rows; 3000 rows in sample, 1063903 estimated total rows
    VACUUM

    udela sice celej tablescan kvuli vacuum, ale pro analyze stejne pouziva jen 3k stranek (da se to nekde zvetsit?). Chtelo by to aby uz kdyz projizdi celou tabulku a generuje io, aby ziskana data laskave pouzil i pro analyze. to snad neni tak tezky nakodit.
  • 8. 3. 2007 15:36

    Pavel Stěhule
    jak je to presne nevim, ale urcite to zavisi od nastaveni statistik.
    postgres=# ALTER TABLE lo ALTER COLUMN x SET statistics 10;
    ALTER TABLE
    postgres=# analyze verbose lo;
    INFO:  analyzing "public.lo"
    INFO:  "lo": scanned 3000 of 4406 pages, containing 681000 live rows and 0 dead rows; 3000 rows in sample, 1000162 estimated total rows
    ANALYZE
    postgres=# ALTER TABLE lo ALTER COLUMN x SET statistics 100;
    ALTER TABLE
    postgres=# analyze verbose lo;
    INFO:  analyzing "public.lo"
    INFO:  "lo": scanned 4406 of 4406 pages, containing 1000000 live rows and 0 dead rows; 30000 rows in sample, 1000000 estimated total rows
    ANALYZE