优化:渴望获取基类实例



Grails应用程序维护有关已保存文档的数据。

为具有称为Document的基本域类的域类创建了简单的域类层次结构。

目前使用的是按子类表的方法。这不是最有效的,但目前还可以。

对文档的访问由ACL控制,ACL是用另一个域类建模的。

在一种特定的情况下,分配给一个ACL的一堆文档必须分配给另一个ACL,而不考虑实例类型(在顶层)。

ACL迫切需要通过声明的批处理来获取文档,以优化读取文档。

class Document {
}
class Image extends Document {
}
class ACL {
  Collection documents
  static mapping = {
     documents   lazy: false, batchSize: 100
  }
}

启用急切获取并没有显著提高性能。

启用了SQL日志记录来分析问题。我发现Document的记录是按预期提取的,但对于每个文档,当使用for循环迭代时,会为文档集合中的每个元素执行带有子类表的附加联接查询。

ACL original = ACL.get(id)
for (doc in original.documents) {
  // Do whatever needs to be done
}

我认为触发这种行为是因为doc没有使用显式类型。我试过这个:

ACL original = ACL.get(id)
for (Document doc : original.documents) {
  // Do whatever needs to be done
}

不幸的是,它没有起到任何作用。

有没有办法告诉Grails,它不会从子类的表中获取数据,因为这是不必要的:只使用基类?

不,没有办法告诉Hibernate(实际上是在做这个,而不是Grails)做那个。如果您需要这种类型的优化,则需要使用原始SQL,而不是基于HQL或GORM的查询。

为了解释为什么这是不可能的,你需要从ORM的角度来考虑这一点。在您在这里展示的域示例中,"文档"没有被保存,"图像"被保存。具体的例子总是"图像",而不是"文档"。为了合并文档列表,ORM不仅必须加载基类的数据,还必须加载实现类的数据。这是不可避免的。避免这种情况会创建一个类的实例,该实例不是域的有效表示形式。

这是使用ORM必须支付的价格之一。

最新更新