[英]Designing hierarchy of parent child relationships with spring data jpa
我正在尝试建立待办事项日志管理员。 我正在将java spring-boot与基于hibernate构建的data-jpa一起使用。 我希望用户拥有该用户从事的多个项目 。 然后,每个项目都有几个与之相关的任务 ,并且用户通过完成简短的原子工作单元( 日志条目 )来跟踪每个任务花费了多少时间。
到目前为止,我最终构建了该系统的最幼稚的实现。 它看起来像是一对多层次结构中的几个级别:用户->项目->任务->条目。 当前的数据库实现基于这样的模式
实体类的代码(为简洁起见,省略了getters setters构造函数和一些注释):
@MappedSuperclass
public abstract class AbstractEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
}
@Entity
public class User extends AbstractEntity {
@Column
private String name;
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private List<Project> projects;
}
@Entity
public class Project extends AbstractEntity {
@Column
private String name;
@OneToMany(mappedBy = "project", fetch = FetchType.LAZY)
private List<Task> tasks;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
@Entity
public class Task extends AbstractEntity {
@Column
private String name;
@OneToMany(mappedBy = "task", fetch = FetchType.LAZY)
private List<Entry> entries;
@ManyToOne
@JoinColumn(name = "project_id")
private Project project;
}
@Entity
public class Entry extends AbstractEntity {
@Column
private Integer duration;
@Column
private LocalDateTime finish;
@ManyToOne
@JoinColumn(name = "task_id")
private Task task;
}
我希望能够为用户提供在用户指定的时间范围内查看所有日志条目的功能 。 我像这样添加了jpa存储库:
public interface EntryRepository extends JpaRepository<Entry, Integer> {
@Query("SELECT e FROM Entry e WHERE (e.task.project.user.id=:user_id) AND " +
"(e.finish BETWEEN :from AND :to)")
List<Entry> getAllForUserInDateRange(@Param("from") LocalDateTime from,
@Param("to") LocalDateTime to,
@Param("user_id") int userId);
}
1)说此查询效率低下是否正确? 我当时认为从数据库执行这样的获取效率不高,因为查询无法利用索引。 由于Entry表中没有外键user_id,因此正在查找每一行,并遵循链入口->任务->项目->用户。 我以线性复杂度而不是对数结尾。
2)解决该问题的更好方法是什么? 将外键存储到用户表中可以吗? 如果我想从数据库中获取特定项目或任务的条目,那么我也必须向这些关系添加外键。 这可以吗?
您应该检查正在执行的真实SQL。 将org.hibernate.SQL
日志级别设置为DEBUG
,您将看到以下语句。
我认为对于您的查询,您实际上将在四个表之间获得三个内部联接。 您说查询无法利用索引。 绝对可以。 创建以下索引:
USER (ID)
PROJECT (USED_ID, ID)
TASK (PROJECT_ID, ID)
ENTRY(TASK_ID, ID)
请参阅使用索引,Luke中的 接触索引 。
使用这些索引,您在四个表之间的联接可能会使用索引。 我不会为此着火,但是应该可以。 检查查询计划。
你是正确的,链ENTRY
- > TASK
- > PROJECT
- > USER
将接踵而至,但它应该是相当faset与indixes
您的数据库架构已非常规范化,这导致在四个表之间进行三个联接。 您可以通过将user_id
引入ENTRY
来对此模式进行非规范化。 这可能会提高查询性能,但老实说,我怀疑这会带来很多好处。 在实际切换到此解决方案之前,您可能需要运行实际基准测试。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.