Spring JPA Hibernate DeleteByColumnName 的效率非常低下。

3
我试图使用Spring的CrudRepository与Hibernate一起使用deleteByColumnName方法通过非主键列删除行。然而,实际执行的查询非常低效,在实践中太慢了。
假设我有两个表ProjectEmployee,每个员工都负责一些项目,这意味着Project表有一个字段employee_id。现在我想通过employee_id删除一些项目。我写了类似于:
public interface ProjectRepository extends CrudRepository<Project, String> {
    @Transactional
    void deleteByEmployeeId(String employeeId);
}

我希望Hibernate能够执行以下查询以实现该方法。
DELETE FROM Project
WHERE employee_id = ?

然而,Hibernate执行起来速度极慢,如下所示:
SELECT id FROM Project
WHERE employee_id = ?

Hibernate将上述结果存储在列表中,并执行。
DELETE FROM Project
WHERE id = ?

执行N次...(虽然是批量执行)

为了解决这个效率问题,我必须通过直接编写 SQL 来重写该方法,比如:

public interface ProjectRepository extends CrudRepository<Project, String> {
    @Query("DELETE FROM Project p where p.employee_id = ?1")
    @Modifying
    @Transactional
    void deleteByEmployeeId(String employeeId);
}

那么行为将与我期望的完全相同。

当我删除包含大约500k条记录的表中的约1k行时,性能会有很大差别。与第二种方法只需250毫秒相比,第一种方法需要45秒才能完成删除!

我使用Hibernate的原因是利用其ORM策略,避免直接使用SQL语言,这样可以长期维护。此时,是否有人知道如何让Hibernate以我的第二种方法执行删除而不直接编写SQL?是否有什么我错过的优化Hibernate性能的东西?

提前致谢!


你是否启用了Hibernate批处理支持? - undefined
2
为了安全地删除,Hibernate 需要先获取实体。如果你使用 deleteById,情况也是一样的。如果没有获取到实体,它就不知道它所拥有的关系和要删除的内容(可能需要根据实体中的关系删除其他实体)。Spring Data 提供了 deleteAllInBatch,它在底层执行查询。所以,如果你想直接执行查询,唯一的办法就是自己指定查询语句。 - undefined
@MaxExplode 感谢您的评论。我已启用批处理,它确实以批处理方式执行。然而,运行查询 "delete from table where id = ?" 耗费了很多时间,成为了减缓执行速度的瓶颈,而 "delete from table where another_field = ?" 只执行了一次。 - undefined
1个回答

1

嗨,欢迎来到stackoverflow。请直接发布一些信息,而不是分享链接。因为链接在将来可能会失效/无效。 - undefined
谢谢,这篇文章真的很有用。所以在这一点上,避免使用Hibernate的默认操作,通过原始查询覆盖方法,并自己处理关系是解决效率问题的唯一途径,对吗? - undefined
是的,你应该编写自己的DELETE语句。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接