代码之家  ›  专栏  ›  技术社区  ›  Andrzej Doyle

Hibernate表/子类继承策略的效率

  •  13
  • Andrzej Doyle  · 技术社区  · 16 年前

    为了给出一个非常简短(经典)的示例,假设您有以下几个类:

    public abstract class Animal {
       int pkey;
       String name;
    }
    
    public class Dog extends Animal {
       long numSlippersChewed; // int is not large enough...
    }
    
    public class Cat extends Animal {
       short miceCaught; // ... but here int is far bigger than required :-)
    }
    

    这些实体的数据库表是有意义的,可以得到很好的非规范化,等等。然而,Hibernate做了什么查询来拉出一个单独的动物?我至少可以想到两种情况:

    1. pet Human 班级。这将存储pkey,因此当Hibernate获取人类对象时,它将需要获取相应的 Animal 我也反对。当给定动物的pkey时,Hibernate将使用什么查询(/ies)来提取和解压实际的动物数据,因为它可能驻留在 Cat Dog 桌子?
    2. HQL,例如 from Animal where name='Rex' (假设名称是唯一的)。这与上面的类似,因为它允许您标识超类表中的一行,但您不知道要检查哪个子类表以获取更多详细信息。HQL是否允许您发出查询 from 抽象类(但是,使用子类特定的东西可以很好地工作,例如。 from Cat where miceCaught > 5 ).

    exists 查询给定pkey的每个子类表,然后从返回命中的表加载。或者,Hibernate可以在所有表中执行一些可怕的联合查询连接——本质上模拟每个层次结构的表,因为结果集将包括所有可能的子类的属性,并返回子类表中的单个选择 null


    如果您有具体类型的子类型,情况也会变得更复杂:

    public class Greyhound extends Dog {
       float lifetimeRacingWinnings;
    }
    

    Greyhound 表,这意味着我的第一种手动检查与pkey对应的类的方法变得更加困难。

    我如此担心的原因是,我希望在一个包含大约70个类的类层次结构上使用这种方法,最大嵌套链为4-5级,因此对所有这些类执行联合查询可能会有 演出Hibernate是否有任何技巧来保持这种相对性能?或者pkey加载对其中一个类的引用需要很长时间?

    3 回复  |  直到 16 年前
        1
  •  8
  •   David M    16 年前

    您会发现Hibernate使用一系列 LEFT JOIN 语句,每个子类一个。因此,随着子类数量的增加,查询速度会变慢,并试图返回更广泛的结果集。因此,您是正确的,它不能很好地扩展大型类层次结构。

    INNER JOIN .

    我还没有尝试过多层次的继承。如果上面的问题还没有让您感到厌烦,建议您试试看——您可以打开SQL调试输出来查看发送到数据库的内容,或者简单地分析数据库。

        2
  •  3
  •   Community Mohan Dere    9 年前

    之后 David M's helpful answer 我决定做一个骨骼测试。

    我创建了一个抽象的超类, ADTestA ADTestG 只有一个整型字段 g 除了 b ADTestB pkey a

    from ADTestA where pkey=1

    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
    

    这不是很漂亮,并且与我希望可以避免的对每个层次表的有效模拟相对应。

    因此,这类查询看起来将非常昂贵。我会考虑需要它们的频率(比如,与知道我想要一个 ADTestP 并立即请求其中一个只加入所需父表的表)。然而,我有一种感觉,这将不可避免地涉及到其他实体;换句话说,从类型为的字段进行一对一映射 阿德斯特拉

    (另一方面,替代战略也不是闪亮的希望灯塔;按照层次结构路由查找表,并且在一个表中包含数百列,这听起来也不是很有效……)

        3
  •  1
  •   Community Mohan Dere    9 年前

    只要您仅通过Hibernate访问数据库,并且您没有重要数据,或者准备编写一个小的迁移脚本,您就应该能够在开发过程的后期就每个子类/层次结构的表做出决定。这就是ORM的优点,它抽象了数据库结构。。。

    Prefer composition over inheritance? )我很怀疑,一个4-5级的70门课的模型不能被简化。。。但我会让你自己想想,毕竟我不知道你想解决什么问题。