一尘不染

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

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 :-)
}

(我在取消getter和setter和Hibernate映射等,只是假设它们是基本的显而易见的情况)。

这些实体的数据库表很有意义,您可以很好地进行非规范化等等。但是,Hibernate为了提取单个动物会做什么查询?我至少可以想到两种情况:

  1. 具有一对一(或一对多)映射的某些其他实体,例如类的pet字段Human。这将存储pkey,因此,当Hibernate提取Human对象时,它也需要提取相应的Animal对象。当给定动物的pkey时,假设它可以驻留在CatDog表中,Hibernate将使用什么查询来提取和解组实际的动物数据?
  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;
}

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

我如此担心的原因是,我将要在具有约70个类的类层次结构中使用此方法,最大嵌套链为4-5级,因此对所有这些执行联合查询可能会很 可怕
性能。Hibernate是否有技巧来保持这种相对出色的表现?还是通过pkey加载对这些类之一的引用会花费很长时间?


阅读 181

收藏
2020-06-20

共1个答案

一尘不染

您会发现,Hibernate使用一系列LEFT JOIN语句(每个子类一个)来编写未知动物类型的查询。因此,查询将随着子类数量的增加而变慢,并将尝试返回越来越大的结果集。所以您是正确的,它在大型类层次结构中无法很好地扩展。

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

我没有尝试使用多个继承级别。如果上述方法尚未解决问题,建议您尝试一下然后看看-
您可以打开SQL调试输出以查看发送到数据库的内容,或者只是对数据库进行概要分析。

2020-06-20