Efficiency of Hibernate's table-per-subclass inheritance strategy

前端 未结 3 572
孤独总比滥情好
孤独总比滥情好 2021-02-07 14:38

I\'m thinking about table layout for a Hibernate-managed class hierarchy, and certainly the table per subclass technique strikes me as the most appropriate in a general sense.

3条回答
  •  無奈伤痛
    2021-02-07 15:01

    After David M's helpful answer I decided to throw together a skeleton test.

    I created an abstract superclass, ADTestA, and 25 concrete subclasses in a three-level hierarchy (I expect you can guess their names). Each class had a single integer field with a name corresponding to its letter - so for example, class ADTestG has a single int field g in addition to the b field it inherits from its immediate parent ADTestB, and the pkey and a fields from the top-level abstract superclass.

    Issuing the HQL query from ADTestA where pkey=1 resulted in the following SQL:

    select adtesta0_.pkey as pkey0_, adtesta0_.a as a0_, adtesta0_1_.b as b1_,
           adtesta0_2_.c as c2_, adtesta0_3_.d as d3_, adtesta0_4_.e as e4_,
           adtesta0_5_.f as f5_, adtesta0_6_.g as g6_, adtesta0_7_.h as h7_,
           adtesta0_8_.i as i8_, adtesta0_9_.j as j9_, adtesta0_10_.k as k10_,
           adtesta0_11_.l as l11_, adtesta0_12_.m as m12_, adtesta0_13_.n as n13_,
           adtesta0_14_.o as o14_, adtesta0_15_.p as p15_, adtesta0_16_.q as q16_,
           adtesta0_17_.r as r17_, adtesta0_18_.s as s18_, adtesta0_19_.t as t19_,
           adtesta0_20_.u as u20_, adtesta0_21_.v as v21_, adtesta0_22_.w as w22_,
           adtesta0_23_.x as x23_, adtesta0_24_.y as y24_, adtesta0_25_.z as z25_,
           case
               when adtesta0_6_.pkey is not null then 6
               when adtesta0_7_.pkey is not null then 7
               when adtesta0_8_.pkey is not null then 8
               when adtesta0_9_.pkey is not null then 9
               when adtesta0_10_.pkey is not null then 10
               when adtesta0_11_.pkey is not null then 11
               when adtesta0_12_.pkey is not null then 12
               when adtesta0_13_.pkey is not null then 13
               when adtesta0_14_.pkey is not null then 14
               when adtesta0_15_.pkey is not null then 15
               when adtesta0_16_.pkey is not null then 16
               when adtesta0_17_.pkey is not null then 17
               when adtesta0_18_.pkey is not null then 18
               when adtesta0_19_.pkey is not null then 19
               when adtesta0_20_.pkey is not null then 20
               when adtesta0_21_.pkey is not null then 21
               when adtesta0_22_.pkey is not null then 22
               when adtesta0_23_.pkey is not null then 23
               when adtesta0_24_.pkey is not null then 24
               when adtesta0_25_.pkey is not null then 25
               when adtesta0_1_.pkey is not null then 1
               when adtesta0_2_.pkey is not null then 2
               when adtesta0_3_.pkey is not null then 3
               when adtesta0_4_.pkey is not null then 4
               when adtesta0_5_.pkey is not null then 5
               when adtesta0_.pkey is not null then 0
           end as clazz_
    from ADTestA adtesta0_
               left outer join ADTestB adtesta0_1_ on adtesta0_.pkey=adtesta0_1_.pkey
               left outer join ADTestC adtesta0_2_ on adtesta0_.pkey=adtesta0_2_.pkey
               left outer join ADTestD adtesta0_3_ on adtesta0_.pkey=adtesta0_3_.pkey
               left outer join ADTestE adtesta0_4_ on adtesta0_.pkey=adtesta0_4_.pkey
               left outer join ADTestF adtesta0_5_ on adtesta0_.pkey=adtesta0_5_.pkey
               left outer join ADTestG adtesta0_6_ on adtesta0_.pkey=adtesta0_6_.pkey
               left outer join ADTestH adtesta0_7_ on adtesta0_.pkey=adtesta0_7_.pkey
               left outer join ADTestI adtesta0_8_ on adtesta0_.pkey=adtesta0_8_.pkey
               left outer join ADTestJ adtesta0_9_ on adtesta0_.pkey=adtesta0_9_.pkey
               left outer join ADTestK adtesta0_10_ on adtesta0_.pkey=adtesta0_10_.pkey
               left outer join ADTestL adtesta0_11_ on adtesta0_.pkey=adtesta0_11_.pkey
               left outer join ADTestM adtesta0_12_ on adtesta0_.pkey=adtesta0_12_.pkey
               left outer join ADTestN adtesta0_13_ on adtesta0_.pkey=adtesta0_13_.pkey
               left outer join ADTestO adtesta0_14_ on adtesta0_.pkey=adtesta0_14_.pkey
               left outer join ADTestP adtesta0_15_ on adtesta0_.pkey=adtesta0_15_.pkey
               left outer join ADTestQ adtesta0_16_ on adtesta0_.pkey=adtesta0_16_.pkey
               left outer join ADTestR adtesta0_17_ on adtesta0_.pkey=adtesta0_17_.pkey
               left outer join ADTestS adtesta0_18_ on adtesta0_.pkey=adtesta0_18_.pkey
               left outer join ADTestT adtesta0_19_ on adtesta0_.pkey=adtesta0_19_.pkey
               left outer join ADTestU adtesta0_20_ on adtesta0_.pkey=adtesta0_20_.pkey
               left outer join ADTestV adtesta0_21_ on adtesta0_.pkey=adtesta0_21_.pkey
               left outer join ADTestW adtesta0_22_ on adtesta0_.pkey=adtesta0_22_.pkey
               left outer join ADTestX adtesta0_23_ on adtesta0_.pkey=adtesta0_23_.pkey
               left outer join ADTestY adtesta0_24_ on adtesta0_.pkey=adtesta0_24_.pkey
               left outer join ADTestZ adtesta0_25_ on adtesta0_.pkey=adtesta0_25_.pkey
     where adtesta0_.pkey=1
    

    That's not very pretty, and does correspond to the effective simulation of the per-hierarchy table that I hoped could be avoided.

    So it looks like these kind of queries are going to be very expensive. I'll have a think about how often they would be needed (compared, say, to knowing that I want an instance of ADTestP and asking for one of those right off the bat which only joins in the required parent tables). I have a feeling however that this will be unavoidable with references from othe entities; in other words, a one-to-one mapping from a field of type ADTestA is always going to involve exactly this kind of lookup.

    (On the other hand the alternative strategies aren't shining beacons of hope either; going the table-per-hierarchy route and having literally hundreds of columns in a single table doesn't sound very efficient either...)

提交回复
热议问题