【问题标题】:Strategies for storing derived data in a normalized relational database在规范化关系数据库中存储派生数据的策略
【发布时间】:2012-08-16 23:52:04
【问题描述】:

我正在使用 Spring 和 Hibernate 编写一个 Web 应用程序,它将人员、组、帖子、附件、cmets 等相当复杂的域模型映射到 mysql 数据库中。这个问题源于尝试优化 cmets 的查询,但也适用于网站的其他方面。

为简化问题,cmets 与帖子具有多:1 关系,而帖子与群组具有多:1 关系。每个组都有一个基本 url ({/group_slug}),每个帖子都可以通过该 url 后跟斜杠和帖子 ID (/{group_slug}/{post_slug}) 访问。这些帖子有对其父级的引用,并以瞬态方法计算它们的 url,该方法向父级询问其 url 并将其 slug 附加到它的末尾。如果评论想要它的 url,它会询问它的父级(帖子),然后查询组并创建 url。它工作正常,除了以下性能问题:

在主页上,我想在一个列表中显示来自每个用户组的所有最近的 cmets。在每条评论下方应该是一个链接,指向该评论所写的帖子。重要的是这是一个相对快速的查询,但是对于当前的模型,我无法弄清楚如何有效地做到这一点。对于用户所属的每个组,我当前的休眠查询 (jpql) 如下所示:

select c from Comment c where c.target.group.id = :groupId and c.dateCreated > :date

但随后要获取目标项目的每个 url(由于休眠急切地加载从评论到目标然后目标到组的一对多关系),目标和组都必须从数据库中加载同样,对于每条评论。

有没有更好的方法来组织这个查询,或者重新设计域模型,这样我就不必每次都加载这么多数据?如果不是,那么每次创建新评论时,对数据库进行反规范化并将评论父级的 url 与它一起存储在数据库中的缺点是什么?没有一个实体经常更改 url,但帖子的 slug 可能会更改。我可以通过在任何 slug 更改上遍历所有关联的 cmets 并更新 url 来处理这种情况,但这似乎仍然违反最佳实践。

【问题讨论】:

  • 在你的域对象中生成一个 url 对我来说似乎不是最佳实践。我不知道你使用什么前端,但是应该在那里生成 url。

标签: mysql hibernate jpa


【解决方案1】:

您可以在查询中急切加载它以防止 SELECT N+1 发生

select c from Comment c join fetch c.target t join fetch t.group g where g.id = :groupId and c.dateCreated > :date

【讨论】:

    猜你喜欢
    • 2016-03-21
    • 2013-09-01
    • 2020-05-21
    • 1970-01-01
    • 2013-01-29
    • 1970-01-01
    • 2013-06-09
    • 2017-01-23
    • 1970-01-01
    相关资源
    最近更新 更多