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

And*_*yle 13 java inheritance database-design hibernate

我正在考虑Hibernate管理的类层次结构的表布局,当然每个子类技术的表格在一般意义上都是最合适的.但是,通过逻辑思考我对其性能有一些担忧,特别是随着子类数量的增加.

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

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 :-)
}
Run Code Online (Sandbox Code Playgroud)

(我正在消除getter和setter以及Hibernate映射等,只是假设它们是基本的明显情况).

这些实体的数据库表是有意义的,你得到了很好的非规范化等等.但是,Hibernate为了拔出一只动物做了什么查询呢?我可以想到至少有两种可能发生这种情况的情况:

  1. 一些其他实体具有一对一(或一对多)映射,例如类的pet字段Human.这将存储pkey,因此当Hibernate获取Human对象时,它也需要获取相应的Animal对象.当给出动物的密钥时,Hibernate将使用什么查询(/ ies)来提取和解组实际的动物数据,因为它可以驻留在CatDog表中?
  2. HQL如from Animal where name='Rex'(让我们假设名称是唯一的).这类似于上面的内容,它允许您在超类表中标识一行,但您不知道要检查哪个子类表以获取更多详细信息.HQL甚至允许您from向抽象类发出查询吗?(尽管使用子类特定的东西很好地工作,例如from Cat where miceCaught > 5).

我可以想到两种方法可以在SQL中完成,而且看起来都不漂亮.一种是exists在给定pkey的每个子类表上运行查询,然后从返回命中的表中加载.或者,Hibernate可以在所有表​​中执行一些可怕的联合查询 - 实质上模拟每层次表的方案,因为结果集将包括所有可能子类的属性,其中子类表中的各个选择返回null不相关的参数.后一种情况甚至可能需要添加一个合成的鉴别器列,以便Hibernate可以知道哪个子类表实际返回了行,因此应该将它们解析为什么Java类.


如果您有混凝土类型的子类型,事情也会变得更加美好:

public class Greyhound extends Dog {
   float lifetimeRacingWinnings;
}
Run Code Online (Sandbox Code Playgroud)

现在对于给定的动物pkey,在Dog Greyhound表中可能存在有效行,这意味着我手动检查对应于pkey的类的第一种方法变得更加困难.

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

Dav*_*d M 8

您会发现Hibernate使用一系列LEFT JOIN语句为未知动物类型编写查询,每个子类一个.因此,随着子类数量的增加,查询将变慢,并将尝试返回更宽的结果集.所以你是对的,它不适合大型类层次结构.

使用HQL,是的,您可以直接查询子类,并访问其属性.然后用单个渲染INNER JOIN.

我没有尝试过多级继承.如果上面还没有让你失望,建议你试试看 - 你可以打开SQL调试输出来查看发送到数据库的内容,或者只是简介你的数据库.