Nakonec stačilo jen se vypovídat, vyspat se a ještě chvíli hledat. Chyba byla 
vydat se cestou view. Řešením je změnit anotace na CiselnikData následujícím 
způsobem:
- vrátit zpět mapování přímo na tabulku - @Table(name="ciselnik_data")
- požadovaného rozlišení podtříd podle business_key se docílí použitím 
@DiscriminatorFormula("(select e.business_key from ciselnik e where e.id = 
ciselnik_id)").

Tím bude v dotazech nad tabulkou osoba generována jen tabulka ciselnik_data, v 
dotazech nad číselníky bude do select klauzule přigenerován uvedený podselekt 
jako sloupec, což je v Oraclu legální. Časy jsou zpět na normálních hodnotách a 
v žádném z vygenerovaných dotazů již není full scan.

Třeba to někomu pomůže. Omlouvám se taky za rozsypaný předmět (nemohl jsem tomu 
předejít před odesláním, asi chyba Centrum mailu).
Tomáš Záluský


______________________________________________________________
> Od: "Tomáš Záluský" <[email protected]>
> Komu: <[email protected]>
> Datum: 30.11.2011 22:33
> Předmět: =?UTF-8?Q?Hibernate, 
> =20v=C3=BDkonnost=20SQL=20dotazu=20nad=20si?=ngle table hierarchií
>
>Dobrý den,
>
>prosím o radu nebo jakýkoli nápad v následujícím problému. Řešíme výkonnost 
>jednoho SQL dotazu vygenerovaného Hibernatem nad "legacy" databází Oracle 9.
>
>Máme následující 3 tabulky (pro srozumitelnost minimalizováno a přejmenováno, 
>ve skutečnosti nejde o osoby):
>
>* ciselnik(id,business_key) - evidence všech číselníků, sloupec business_key 
>je unikátní
>* ciselnik_data(id,ciselnik_id,hodnota) - data pro jednotlivé číselníky 
>sloučená do jedné tabulky, ciselnik_id odkazuje na ciselnik.id
>* osoba(id,jmeno,zamestnani_id,pohlavi_id) - osoby, sloupce zamestnani_id a 
>pohlavi_id odkazují na ciselnik_data.id, předpokládá se, že referencovaný 
>řádek patří ke správnému číselníku.
>
>(Příklad:
>
>ciselnik: 
>1 | ZAMESTNANI
>2 | POHLAVI
>
>ciselnik_data:
>1 | 1 | truhlář
>2 | 1 | učitel
>3 | 1 | prodavač
>4 | 2 | muž
>5 | 2 | žena
>
>osoba:
>1 | Láďa  | 1 | 4
>2 | Lenka | 2 | 5
>3 | Lukáš | 2 | 4
>)
>
>V Javě je každý číselník modelován jako samostatná třída, tyto třídy mají 
>společného předka CiselnikData s anotací 
>@Inheritance(strategy=InheritanceType.SINGLE_TABLE) a @DiscriminatorColumn, 
>samy si jen specifikují hodnotu discriminatoru. Ve třídě Osoba tak mohou být 
>přímo property typu Zamestnani a Pohlavi a tyto jsou nepovinné. 
>
>Dosud byla třída CiselnikData mapována na tabulku ciselnik_data a 
>discriminator byl provizorně sloupec ciselnik_id. V SQL dotazu pro výběr osoby 
>pak vypadaly joiny takto:
>
>from osoba, ciselnik_data ciselnik_data_1, ciselnik_data ciselnik_data_2
>where osoba.zamestnani_id = ciselnik_data_1.id(+) and osoba.pohlavi_id = 
>ciselnik_data_2.id(+)
>
>Rozlišování číselníků podle id je však nespolehlivé a proto jsme chtěli použít 
>k tomu určený sloupec business_key. Vytvořili jsme view ciselnik_view, což je 
>join tabulek ciselnik a ciselnik_data. Třídu CiselnikData jsme namapovali na 
>toto view, discriminatorem se stal sloupec business_key.
>
>Problém je, že vygenerovaný dotaz je nyní
>
>from osoba, ciselnik_view ciselnik_view_1, ciselnik_view ciselnik_view_2
>where osoba.zamestnani_id = ciselnik_view_1.id(+) and osoba.pohlavi_id = 
>ciselnik_view_2.id(+)
>
>a exekuční plán tohoto dotazu obsahuje full scan, což v praxi znamená zhoršení 
>z 9 na 500ms. Zřejmě inner join ve view do dotazu zatáhl tabulku ciselnik a 
>databáze nemá šanci domyslet si, že data pocházejí z jediného číselníku. 
>
>Přišli jsme na to, že full scan zmizí při aplikaci kteréhokoli z opatření:
>
>- doplněním podmínky: and ciselnik_view_1.business_key(+) = 'ZAMESTNANI' and 
>ciselnik_view_2.business_key(+) = 'POHLAVI'
>- doplněním hintu /*+NO_MERGE*/
>- odstraněním outer joinu (jen pro úplnost, vzhledem k  logice aplikace 
>nepřijatelné)
>
>Zajímalo by mne, zda by bylo možné vygenerovaný dotaz ovlivnit, aby nejlépe 
>dosadil podmínku nebo alespoň doplnil hint. Zkoušeli jsme anotaci 
>@ForceDiscriminator na CiselnikData, ale podle všeho se zdá, že nemá dosah 
>ovlivnit SQL pro tabulku osoba. Nefungovalo ani použití @Where ve třídě Osoba. 
>Nenašel jsem ani nic relevantního na google potažmo stackoverflow.
>
>Díky za jakýkoli postřeh.
>
>Tomáš Záluský
>

Odpovedet emailem