我具有以下设计(伪代码):
table A (id int, cond int)
table B (id int, a_id int)
也就是说,B.a_id
是A.id
的外键。并非B引用了A中的所有条目。B包含的条目比A还要多。
A和B之间的关系仅用B表示,而不用A表示:
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "a_id")
private A a;
我想为此SQL建立JPA标准查询(查询1)
select A.* from A where A.id in (select distinct B.a_id from B) or A.cond = 1
此刻我找到了解决方案:
EntityManager em = ...
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<A> qa = cb.createQuery(A.class);
Root<A> ra = qa.from(A.class);
Subquery<B> sqb = qa.subquery(B.class);
Root<B> srb = sqb.from(B.class);
qa = qa.select(ra).distinct(true).where(cb.or
(
cb.equal(ra, srb.get(B_.a))
, cb.equal(ra.get(A_.cond), 1)
));
em.createQuery(qa).getResultStream().forEach(System.out::println);
EclipseLink将其转换为A
和B
之间的联接以及最终的distinct
选择(查询2)
SELECT DISTINCT t0.ID, t0.COND FROM A t0, B t1 WHERE ((A.ID = B.A_ID) OR (A.COND = ?))
bind => [1]
但是,由于B
的条目太多,所以我想知道第一个select distinct B.a_id from B
是否会更好。
在where子句中带有子查询的查询1的相应JPA条件查询表达式是什么?
(我想知道解决方案,尽管该数据库具有查询优化器,并且可以选择估计的最佳执行路径)
编辑
对于我的数据和索引,查询优化器为查询1选择一个执行计划,估计成本为3,而对查询2估计为7。
还有另一种形式(查询3)
select A.* from A where exists (select 1 from B where B.a_id = A.id) or A.cond = 1
查询优化器为其选择与查询1相同的执行计划。
qa = qa.select(ra).distinct(true).where(cb.or
(
cb.exists(qb.select(rb).where(cb.equal(ra, rb.get(B_.a))))
, cb.equal(ra.get(A_.cond), 1)
));