【问题标题】:Hibernate QueryImpl.list optimizationHibernate QueryImpl.list 优化
【发布时间】:2013-04-11 05:52:27
【问题描述】:

我有一个包含 144 条记录(行)的任务表。我正在使用普通的选择查询获取所有记录,但是 JProfiler 报告的方法所花费的时间对于这么少量的数据来说太多了。

Here 是 JProfiler 的快照。

我关心的是 org.hibernate.impl.QueryImpl.list 所花费的时间。当我在数据库工具中运行普通 sql 查询时,获取所有记录需要 0.016 秒,但这里需要更多时间。

我怎样才能减少这个时间以及减少到什么程度?这真的可以减少吗?或者大约 3 秒就可以了?

使用的数据库是MySql。

下面是获取日期的方法

public List<Backlog> findBacklogList() {
    Query query = (Query) getSession().createQuery("from Backlog");
    List<Backlog> backlogList = (List<Backlog>) query.list();
    return backlogList;
}

下面是积压的Pojo

public class Backlog implements Serializable {

/**
 * 
 */
private static final long serialVersionUID = 1L;
private Long taskId;
private String taskName;
private TaskType taskType;
private Member createdBy; // String
private Date createdDate;
private Member updatedBy; // String
private Date updatedOn;
private Status status;
private Priority priority;
private String approved;
private Member completedBy;
private Member ownedBy;
private BacklogGroup group;
private Set<OtherPeople> otherPeople;
private String activeStatus;
private String statusChanged;
private String description;
private Date expectedEndDate;

/**
 * @return the taskId
 */
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "taskid", nullable = false, unique = true, insertable = false)
public Long getTaskId() {
    return taskId;
}

/**
 * @param taskId
 *            the taskId to set
 */
public void setTaskId(Long taskId) {
    this.taskId = taskId;
}

/**
 * @return the taskName
 */
@Column(name = "taskname", nullable = false, unique = true)
public String getTaskName() {
    return taskName;
}

/**
 * @param taskName
 *            the taskName to set
 */
public void setTaskName(String taskName) {
    this.taskName = taskName;
}

/**
 * @return the taskType
 */
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "tasktype", referencedColumnName = "id", nullable = false)
public TaskType getTaskType() {
    return taskType;
}

/**
 * @param taskType
 *            the taskType to set
 */
public void setTaskType(TaskType taskType) {
    this.taskType = taskType;
}

/**
 * @return the createdDate
 */
@Column(name = "createdDate", nullable = false)
public Date getCreatedDate() {
    return createdDate;
}

/**
 * @param createdDate
 *            the createdDate to set
 */
public void setCreatedDate(Date createdDate) {
    this.createdDate = createdDate;
}

/**
 * @return the updatedBy
 */
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "updatedBy")
public Member getUpdatedBy() {
    return updatedBy;
}

/**
 * @param updatedBy
 *            the updatedBy to set
 */
public void setUpdatedBy(Member updatedBy) {
    this.updatedBy = updatedBy;
}

/**
 * @return the updatedOn
 */
@Column(name = "updatedOn")
public Date getUpdatedOn() {
    return updatedOn;
}

/**
 * @param updatedOn
 *            the updatedOn to set
 */
public void setUpdatedOn(Date updatedOn) {
    this.updatedOn = updatedOn;
}

/**
 * @return the status
 */
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "status", referencedColumnName = "id", nullable = false)
public Status getStatus() {
    return status;
}

/**
 * @param status
 *            the status to set
 */
public void setStatus(Status status) {
    this.status = status;
}

/**
 * @return the priority
 */
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "priority", referencedColumnName = "id", nullable = false)
public Priority getPriority() {
    return priority;
}

/**
 * @param priority
 *            the priority to set
 */
public void setPriority(Priority priority) {
    this.priority = priority;
}

/**
 * @return the approved
 */
@Column(name = "approved")
public String getApproved() {
    return approved;
}

/**
 * @param approved
 *            the approved to set
 */
public void setApproved(String approved) {
    this.approved = approved;
}

/**
 * @return the completedBy
 */
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "completedBy")
public Member getCompletedBy() {
    return completedBy;
}

/**
 * @param completedBy
 *            the completedBy to set
 */
public void setCompletedBy(Member completedBy) {
    this.completedBy = completedBy;
}

/**
 * @return the otherPeople
 */
@OneToMany(mappedBy = "task", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
public Set<OtherPeople> getOtherPeople() {
    return otherPeople;
}

/**
 * @param otherPeople
 *            the otherPeople to set
 */
public void setOtherPeople(Set<OtherPeople> otherPeople) {
    this.otherPeople = otherPeople;
}

/**
 * @return the group
 */
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "groupid", referencedColumnName = "id", nullable = false)
public BacklogGroup getGroup() {
    return group;
}

/**
 * @param group
 *            the group to set
 */
public void setGroup(BacklogGroup group) {
    this.group = group;
}

/**
 * @return the createdBy
 */
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "createdBy", nullable = false)
public Member getCreatedBy() {
    return createdBy;
}

/**
 * @param createdBy
 *            the createdBy to set
 */
public void setCreatedBy(Member createdBy) {
    this.createdBy = createdBy;
}

/**
 * @return the activeStatus
 */
@Column(name = "activeStatus")
public String getActiveStatus() {
    return activeStatus;
}

/**
 * @param activeStatus
 *            the activeStatus to set
 */
public void setActiveStatus(String activeStatus) {
    this.activeStatus = activeStatus;
}

/**
 * @return the statusChanged
 */
@Column(name = "statusChanged")
public String getStatusChanged() {
    return statusChanged;
}

@Column(name = "expectedEndDate")
public Date getExpectedEndDate() {
    return expectedEndDate;
}

public void setExpectedEndDate(Date expectedEndDate) {
    this.expectedEndDate = expectedEndDate;
}

/**
 * @param statusChanged
 *            the statusChanged to set
 */
public void setStatusChanged(String statusChanged) {
    this.statusChanged = statusChanged;
}

/**
 * @return the description
 */
@Column(name = "description", length = 5000)
public String getDescription() {
    return description;
}

/**
 * @param description
 *            the description to set
 */
public void setDescription(String description) {
    this.description = description;
}

/**
 * @return the ownedBy
 */
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ownedBy", nullable = false)
public Member getOwnedBy() {
    return ownedBy;
}

/**
 * @param ownedBy the ownedBy to set
 */
public void setOwnedBy(Member ownedBy) {
    this.ownedBy = ownedBy;
}

/*
 * (non-Javadoc)
 * @see java.lang.Object#hashCode()
 */
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((taskId == null) ? 0 : taskId.hashCode());
    return result;
}

/*
 * (non-Javadoc)
 * @see java.lang.Object#equals(java.lang.Object)
 */
@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (!(obj instanceof Backlog)) {
        return false;
    }
    Backlog other = (Backlog) obj;
    if (taskId == null) {
        if (other.taskId != null) {
            return false;
        }
    } else if (!taskId.equals(other.taskId)) {
        return false;
    }
    return true;
}

}

【问题讨论】:

  • 发布正常查询,获取所有数据需要 0.016 秒。
  • 从积压中选择 *
  • 正如 koljaTM 所说,您的 Backlog 类有各种相关的 pojo,它们被设置为热切地获取。因此,当您获取此查询以获取此关联数据时,也会执行。延迟加载关联的属性是一种很好的做法,它将减少获取 Backlog 数据所需的时间。
  • 感谢 code13,延迟获取起到了作用,并将时间减少到 1205 毫秒,但同样,org.hibernate.PersistentSet.isEmpty 正在被调用,这额外花费了 1705 毫秒加上该方法出来的总时间为 3 秒。在这种情况下还能做些什么? jprofile snapshot

标签: mysql hibernate query-optimization hql


【解决方案1】:

我的猜测是查询也会获取所有相关数据,例如otherPeople 集,可能很大。尝试激活休眠 sql 日志记录以查看实际执行了哪些语句。如果您为每个结果行(甚至多个)获得一个单独的子查询,您可能会遇到问题。考虑不要急切地获取或设置一些与 FetchJoin 的关系,以便数据立即连接,如果您知道您将需要它。 如果您不需要数据,请不要选择它。有时,如果您对大量结果感兴趣,但只对其中的一小部分数据感兴趣(例如,对于概览列表),构建一个额外的对象仅用于查询也是一个好主意。

【讨论】:

  • 感谢 koljaTM,懒惰的提取起到了作用并将时间减少到 1205 毫秒,但同样,org.hibernate.PersistentSet.isEmpty 正在被调用,这额外花费了 1705 毫秒加上该方法出来的总时间为 3 秒。在这种情况下还能做些什么?
【解决方案2】:

在使用 Hibernate 时减少获取数据所需时间的第一件事是尽可能使用延迟加载。

@ManyToOne(fetch = FetchType.EAGER)// This will take more time 

如果可能,在您的 pojo 中将 EAGER 加载更改为 LAZY。

@ManyToOne(fetch = FetchType.LAZY)

另一件事是启用打印 Hibernate 执行的查询,您可以看到执行了多少实际查询来获取单个对象。

您可以通过在 hibernate 配置中将 hibernate.show_sql 属性设置为 true 来做到这一点。

<property name="show_sql">true</property>

您可以在here 阅读有关休眠优化的更多信息。

【讨论】:

  • 嗨,code13,我已经这样做并减少了时间,但是正如您在上面的 cmets 上看到的那样,PersistentSet 类的时间存在新问题。请参考snapshot
猜你喜欢
  • 1970-01-01
  • 2010-10-05
  • 2016-01-23
  • 1970-01-01
  • 1970-01-01
  • 2013-02-26
  • 2014-11-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多