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ý
