【问题标题】:ActiveJDBC eager loading of Polymorphic ParentsActiveJDBC 预加载多态父节点
【发布时间】:2016-08-23 03:45:53
【问题描述】:

我无法急切地加载子类的多态父类。 include 语句似乎没有任何区别。

儿童班:

@BelongsToPolymorphic(
    parents = {ParentRequest.class},
    typeLabels  = {"parent_request"})
public class Child extends Model {
}

父类:

public class ParentRequest extends Model {

}

应该急切返回子+父的查询:

List<Child> children = Child.where("... limit 500").include(ParentRequest.class);

children.size(); //this gives me 500
children.cachedParents.size(); //this gives me 0;

最终,我正在尝试加快以下操作:

for (Child child : children) {
     ParentRequest pr = child.parent();
     // lots of pr.getString("parent_field");
     ...
 }

我已经对这些操作进行了基准测试,无论是否在 Child.where() 方法上使用 .include(ParentRequest.class),上述操作似乎都需要大约 67 毫秒。

非常感谢任何见解或帮助。

注意:我知道孩子只有一个父母。在不久的将来它将有几个。

编辑: 由于某些原因,反转查询产生了更快的结果。也就是说,如果我搜索 ParentRequest 并包含 Child,则操作会快得多,而不是查找 Children 并包含 ParentRequest。请注意,我专门做了一个 findBySql 将子表连接到结果中的 parent_request 表。下面我留下了查询的细节。

List<ParentRequest> parents = ParentRequest.findBySQL("SELECT child.*, parent_requests.* " +
                "FROM child JOIN parent_requests ON child.parent_id=parent_requests.id WHERE " +
                "RAND()<=? AND (child.metersToA BETWEEN ? AND ?) " +
                        " AND (child.metersToB BETWEEN ? AND ?) limit ?",
                decimation_value,
                minDistanceToA, maxDistanceToA ,
                minDistanceToB, maxDistanceToB,
                MAX_POINTS).include(Child.class);

【问题讨论】:

    标签: java polymorphic-associations activejdbc eager


    【解决方案1】:

    我编写了一个简单的测试并启用了日志记录

    Article article = Article.findById(1);
    article.add(Comment.create("author", "tjefferson", "content", "comment 1"));
    article.add(Comment.create("author", "tjefferson", "content", "comment 2"));
    LazyList<Comment> comments = Comment.where("author = ?", "tjefferson").include(Article.class);
    
    System.out.println(comments.size());// does loading of data, prints 2
    Article parent1 = comments.get(0).parent(Article.class); // does not generate DB query
    Article parent2 = comments.get(1).parent(Article.class); // does not generate DB query
    
    assert (parent1 == parent2); // true
    

    执行此代码会将以下内容记录到控制台:

    SELECT * FROM comments WHERE author = ?", with parameters: <tjefferson>, took: 1 milliseconds
    SELECT * FROM articles WHERE id IN (?)", with parameters: <1>, took: 1 milliseconds
    

    如您所见,数据库只有两个查询。 此外,您提到的那一行:

    children.cachedParents.size(); //this gives me 0;
    

    不会编译,因为LazyList 没有成员cachedParents

    如果你在这种情况下循环遍历孩子,并得到一个像这样的父母:

    child.parent(Parent.class)
    

    ,由于对象缓存在内存中,因此不会对数据库进行数据库查询。

    框架按预期工作。 使用和不使用 include() 的时间相同的原因是数据集的大小。 67 毫秒相当快,“瓶颈”在别处。

    您需要做的是加载更大的数据集以查看差异。

    此外,请记住,加载的数据越多,分配的堆空间就越多。最终,include() 方法解决了 N+1 问题 (http://javalite.io/lazy_and_eager),但这并不意味着您的应用程序会更快。您需要进行试验,并决定是否最好在您的情况下使用它。

    总结: 如果使用include() 方法,对数据库的调用会更少,但会分配更多的 RAM。由您决定它是否对您的应用程序更快。

    【讨论】:

    • 感谢您的快速回复!成员 children.cachedParents.size 是我可以在调试器中看到的,所以我无法解释为什么我有它而你没有。无论出于何种原因,我发现如果我反转搜索,即执行连接两个表的查询,然后使用 include(Child.class) 拉出 ParentRequest,我会获得更好的性能。查询我上面的方式大约需要 25-35 秒才能返回 500 分。查询我在此评论中提到的方式使我能够在 12-15 秒或更短的时间内返回 500 分。我将在下面发布我的伪代码。
    • 我很高兴看到框架按预期工作(我确信 100 次中有 99 次都是这种情况)。我想知道我可以做些什么不同的事情。
    • 启用日志记录:javalite.io/logging 并查看在您的情况下生成了哪些查询。之后,您可以在 DB 控制台中手动运行这些,运行解释并找出为什么有些更快而另一些更慢。 ActiveJDBC 只是一个工具 - 它为您提供选项:)
    • 刚刚看到您的编辑。您的查询可能比包含更有效。首先,include 会找到直接的对象,然后是相关的。在您的情况下,您可以只为List&lt;ParentRequest&gt; 获取您需要的所有内容,因此您只需一个查询即可逃脱。此外,您的查询从两个表中收集值,这可能不是最好的:javalite.github.io/activejdbc/snapshot/org/javalite/activejdbc/… 请参阅findBySQL 的文档:确保查询返回与此模型关联的所有列...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多