我希望为结果提供内容过滤。我的(为简洁而编辑)实体如下所示:
节点:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Node {
@Id
@GeneratedValue
public Integer id;
}
场景:
@Entity
public class Scene extends Node {
@OneToMany(mappedBy = "scene", /*fetch = FetchType.EAGER, */cascade = CascadeType.ALL)
public List<Source> sources;
}
来源:
@Entity
public class Source extends Node {
@ManyToOne
public Scene scene;
@Enumerated(EnumType.ORDINAL)
public SourceType type;
}
以下是我希望实现的过滤器示例。
给定SourceTypes的集合,我希望选择所有场景,使得这个场景由这些类型中的每一个的源引用。我使用带有以下谓词的QueryDSL实现了这一点:
private Predicate filterBySourceType(Collection<SourceType> it) {
BooleanBuilder bb = new BooleanBuilder();
for (SourceType st : it)
bb.and(QScene.scene.sources.any().type.eq(st));
return bb.getValue();
}
将一系列这些谓词组合在一起以提供整体查询。甚至只选择一个SourceType时,生成的查询如下所示:
Hibernate: select count(scene0_.id) as col_0_0_ from Scene scene0_ inner join Node scene0_1_ on scene0_.id=scene0_1_.id where exists (select 1 from Source source1_ inner join Node source1_1_ on source1_.id=source1_1_.id where (source1_.id in (select sources2_.id from Source sources2_ inner join Node sources2_1_ on sources2_.id=sources2_1_.id where scene0_.id=sources2_.scene_id)) and source1_.type=?)
我相信上面发生的是交叉连接,因此(2k场景,1k源)查询需要几秒钟。
我尝试切换到具体的类多态,以消除Node连接,但没有明显的性能提升。
我如何优化该谓词?
答案 0 :(得分:3)
事实证明,您可以使用JPASubQuery获取CollectionExpression并写出查询,类似于使用普通旧SQL编写它的方式。
bb.and(QScene.scene.in(
new JPASubQuery()
.from(source)
.where(source.type.eq(st))
.list(source.scene)
));