Optimalizujeme Hibernate

Při vývoji s Hibernate můžete narazit na výkonnostní problémy. Tento fakt je způsoben především tím, že Hibernate přidává další abstraktní vrstvu a pokud Vám jeho funkčnost není zcela známa, můžete narazit na problémy.

Chtěl bych zde osvětlit postupy, které my používáme při vývoji aplikací, abychom dosáhli co nejvyššího výkonu. Vysvětlení pojmů a samotné postupy na optimalizaci si můžete přečíst v článku Hibernate a optimalizace.

Vypnout second level-cache

První pravidlo je, že při vývoji máme vypnutou co největší část second level cache. Pokud je totiž cache zapnutá, nedozvíte se skutečně prováděné dotazy. Obvykle se totiž při vývoji díváte na tu samou stránku opakovaně a dotazy jsou cachovány z předchozích požadavků. Tím, že cache vypnete, se dotazy provádí pokaždé. Pokud je pak cache v provozním prostředí zapnutá, je výkon obvykle už jen lepší.

Optimalizujte vždy jeden požadavek

Cílem je optimalizovat především jednotlivé požadavky, aby byly co nejrychlejší. Později se můžete zaměřit např. na skupinu požadavků (např. dle statistiky skutečných přístupů na produkční server) a optimalizovat použití cache a přístupů do databáze. Nicméně nyní se zaměřme jen na jeden požadavek.

Zapněte logování dotazů

V konfiguraci je možné zapnout logování dotazů od Hibernate. K tomu použijte tyto parametry:

  • hibernate.show_sql=true – zobrazuj v logu dotazy
  • hibernate.use_sql_comments=true – do dotazů vkládej původní Hibernate dotaz jako koměntář.

V logu se pak začnou objevovat dotazy:

Hibernate: /* from Hrad this where this.name = :p_name */ select hrad0_.I_D as I1_28_, hrad0_.version as version28_, hrad0_.NAME as NAME28_ from HRAD hrad0_ where hrad0_.NAME=? limit ?
Hibernate: /* criteria query */ ...
Hibernate: /* load collection Hrad.strasidla */ ...
Hibernate: /* load cz.softeu.evidence.UserAccountImpl */ ...

Takto budete mít při vývoji vždy rychlý přehled o tom, kolik dotazů se provádí. Díky komentáři také můžete snadno zjistit o jaký typ dotazu se jedná.

Použijte P6Spy

Pokud se podíváte na výsledky logované Hibernate, zjistíte, že je v nich místo skutečných hodnot uložen jen ?. Proto potřebujeme podrobnější zaznamenávání informací o dotazech.

K těmto účelům vznikl JDBC wrapper s názvem P6Spy. Jedná se o jednoduchý nástroj, který použijete jako JDBC takto:
Do persistence.xml uvedete místo svého obvyklého JDBC driver class (např. org.postgresql.Driver) toto:

<property name="hibernate.connection.driver_class" value="com.p6spy.engine.spy.P6SpyDriver"/>

Následně přidáte do projektu závislost na P6Spy.jar a nahrajete do lokální repozitory:

                        <dependency>
                                <groupid>p6spy</groupid>
                                <artifactid>p6spy</artifactid>
                                <version>1.3</version>
                        </dependency>

Nyní vytvoříte soubor spy.properties a v něm zkontrolujte nastavení položky realdriver

realdriver=org.postgresql.Driver
realdriver2=com.mysql.jdbc.Driver
realdriver3=

Jak vidíte, je možné mít současně podporu pro více JDBC driverů. V produkci pak obvykle soubory p6spy.jar a spy.properties necháváme v distribučním balíku a jen měníme nastavení driver_classpersistence.xml.

Nyní když spustíte aplikaci, vytvoří se soubor spy.log, který obsahuje informace o provedených dotazech.

Zjistěte, který požadavek je pomalý

Nyní je potřeba se na dotazy podívat statisticky a najít:

  • pomalé dotazy – ty je potřeba optimalizovat přepsáním či přidáním indexů
  • opakované dotazy – tyto dotazy je dobré neprovádět vícekrát. Buď upravit strukturu programu nebo zavést cachování (stačí obvykle i po dobu jednoho dotazu)
  • časté dotazy – dotazy, které se provádějí často, ale např. pokaždé s–jiným parametrem a pokusit se o jejich eliminaci nebo sloučení
  • kolik řádků a jak velká data nám byla vrácena

My používáme open source program IronTrackSQL. Nicméně jeho výrobce (IronGrid) již neexistuje a program se špatně shání. Proto si jej můžete stáhnout i od nás (je pod APL licencí). Nicméně stále je na archive.org k dispozici stránka produktu a Fast Facts.

V podstatě se jedná o jednoduchou aplikaci, která umí otevřít výstup z programu P6Spy a zobrazit jej. Dotazy seskupuje jak s parametry tak i bez nich. Dotazy pak dokáže řadit podle počtu, maximální délky a průměrné délky.

Můžete tak snadno identifikovat problémy a opravit je. Z aplikace můžete i snadno problémové dotazy zkopírovat.

Protože IronTrackSQL již není udržován, vznikl v poslední době nový projekt elvyx.com, který by jej měl nahradit.

5 thoughts on “Optimalizujeme Hibernate”

  1. Myslim, ze vetsina z uvedenych praktik je vhodna pro optimalizaci prace s databazi obecne. Ale jinak pekne popsane. Dekuji.

  2. Zdravim, nemate skusenosti s integraciou P6Spy s c3p0 poolom a hibernate ? Pretoze sa to akuratne snazim spojazdnit, ale nechce najst drajver. Vdaka. Inak super clanok 😉

  3. Zdravím,

    my běžně používáme P6Spy + c3p0 + Hibernate. Použití c3p0 je transparentní a nemusíte nic nastavovat (samozřejmě hibernate, aby jej používal). Takže uvedený návod je platný pro všechny connection pooling nástroje, které podporuje Hibernate.

  4. Zdravím,

    nesouhlasím s tím, že při vývoji má být vypnutá second level-cache. Ono jde při vývoji také o to, nastavit správně objekty pro second level cache. Takže já ji doporučuji mít od samého začátku zapnutou. A navíc, není problém programově tuto second-level cache kdykoliv vyprazdnit.

    Tento článek se jmenuje „optimalizace hibernate“, ale defacto pouze říká obecné věci. Pokud se ale hibernate používá na rozsáhlých projektech (stovky tříd), pak bych se při optimalizaci zaměřil na toto – ve zkratce:
    – řádně nastavit, které objekty se mají cachovat (např. číselníky, či často používané třídy)
    – pokud to není nutné, je výrazně rychlejší nevracet si instance objektů z DB, ale vracet si jen potřebné atributy
    – pokud se provádí UPDATE, DELETE na více objektech najednou, je lepší použít tzv. BULK UPDATE/DELETE
    – správně nastavit isolation level pro DB
    – při sestavování dotazů je třeba je navrhovat optimalizovaně a nespolehat se, že databáze je správně z optimalizuje
    – při sestavování dotazů je možno použít klíčového slova FETCH
    – správné nastavení cache providera
    – vytvářet regiony v cachi -> každá skupina objektů má potom jinou platnost
    – atd.

  5. David Vach: Máte naprostou pravdu a souhlasím se vším co jste napsal.

    Nicméně můj seznam je jen základem toho, aby uživatel Hibernate měl přehled o tom, co se v něm děje. Pokud bych zde rozepsal vše, článek by nebyl tak čtivý a neměl by tak jasné sdělení – i v Hibernate můžete mít snadno pod kontrolou, co se děje a že většina optimalizací je shodná s normálním SQL.

Napsat komentář: David Vach Zrušit odpověď na komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *