将派生数据存储在规范化关系数据库中的策略

时间:2012-08-16 23:52:04

标签: mysql hibernate jpa

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

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

在主页上,我想在单个列表中显示每个用户组的所有最近评论。每条评论下面都应该是评论所写帖子的链接。重要的是这是一个相对快速的查询,但对于当前模型,我无法弄清楚如何有效地执行此操作。我当前的hibernate查询(jpql)看起来像这样,对于用户所属的每个组:

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

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

是否有更好的方法来组织此查询,或重新设计域模型,以便我不必每次都加载这么多数据?如果没有,每次创建新评论时,对数据库进行反规范化并将注释的父级的url存储在数据库中的缺点是什么?没有任何实体经常更改网址,但是帖子的网格可能会发生变化。我可以通过循环遍历任何slug更改和更新url的所有相关注释来处理这种情况,但它似乎仍然违反了最佳做法。

1 个答案:

答案 0 :(得分:0)

您可以在查询中急切加载它以防止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