【问题标题】:Hibernate - Query becomes slow when I want to skip conditionHibernate - 当我想跳过条件时查询变慢
【发布时间】:2021-04-23 13:43:51
【问题描述】:

我有以下示例查询,它在

Query qry = em.createQuery(
              "select e from Example e where e.ids in :ids ")
              .setParameter("ids", ids); // List<String> ids 

由于列表可以为 null 或为空,我包含了以下在数据库端同样快速终止的简单条件检查:

Query qry = em.createQuery(
              "select e from Example e where (:idFilterUsed = false OR e.ids in :ids ) ")
              .setParameter("ids", ids) // List<String> 
              .setParameter("idFilterUsed", idFilterUsed); // boolean 

即使较低的查询似乎只有一个小的琐碎条件,查询和映射也需要 12 到 20 秒,而不是

我无法解释我已经做了什么,什么没有帮助我:

  • 使用 .createNativeQuery 并在 Example.class 中解析结果
  • 使用整数 (0/1) 而不是布尔参数
  • 在 OR 条件内更改顺序

任何人都知道它可能是什么,或者如果存在条件,是否有替代方法可以抛出此类 IN 查询?我的许多查询都需要几个这样的条件检查。

查询在 Oracle 12g 数据库上运行,我使用 Hibernate 5.4.27。

编辑:为了避免误解 -> 如果输入列表 (ids) 填充了至少一个 IDidFilterUser = true,则查询具有这种极端的性能损失。当列表为空时,查询速度很慢是合乎逻辑的,但实际上这并没有影响,因为它附加了更多的条件。

【问题讨论】:

  • 性能不好是因为如果id列表为空,你会加载一个表的所有内容,所以数据库必须进行全表扫描并通过网络传输所有数据所以然后 Hibernate 可以从中实现对象。您应该限制要获取的数据量,例如.setMaxResults(10)
  • 嘿克里斯蒂安,谢谢您的回复。如果 id 列表为空,则 idFilterUsed 设计为 false。 OR 条件不会在 IN 语句之前终止吗?在数据库方面似乎是这样,至少查询时间告诉我。
  • 正确的idFilterUsedfalse,因此查询会返回所有行。这就是性能不佳的原因。
  • 你是对的,但我也遇到了问题,当idFilterUsed = true (并且 :ids 甚至填充了一个(!)单个 id )时,这对我来说根本没有意义。我描述的问题与使用 Hibernate 和在数据库本身上返回很少结果(行大小
  • 我猜你缺少一个索引,当你尝试通过 SQL 编辑器执行它时,你很幸运,数据仍在数据库的页面缓存中,所以速度更快。

标签: sql hibernate jpa


【解决方案1】:

子句:idFilterUsed = false与数据库无关。

我建议两个适当的选项来跳过条件:

1.对于一个可选参数

if(idFilterUsed) {
   qry = em.createQuery(
                  "select e from Example e where e.ids in :ids")
                  .setParameter("ids", ids);
} else {
   qry = em.createQuery("select e from Example e");
}

2. 对于多个可选参数,请使用Criteria APISpring Specification

public class ExampleSpecification {

    public static Specification<Example> idIn(List<Long> ids, boolean idFilterUsed) {
        return (root, query, builder) -> {
            if (!idFilterUsed) {
                return builder.conjunction();
            }
    
            return root.get("ids").in(ids);
        };
    }
}

public interface ExampleRepository
        extends JpaSpecificationExecutor<Example> {
}

List<Long> ids = Arrays.asList(1L, 2L, 5L);
boolean idFilterUsed = false;

exampleRepository.findAll(ExampleSpecification.idIn(ids, idFilterUsed));

看一个例子here

【讨论】:

    猜你喜欢
    • 2012-05-01
    • 2022-10-24
    • 2022-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-17
    • 2022-12-14
    相关资源
    最近更新 更多