JPA:限制查询结果数量|返回的行数

JPA : Restrict query result number | Number of rows returned

我要求一次最多 return 10 个结果。我使用 Criteria Builder 构建查询并应用 setMaxResults(10) 来限制 returned 行。

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Customer> q = cb.createQuery(Customer.class);
Root<Customer> c = q.from(Customer.class);
q.select(c);
q.distinct(true);
List<Predicate> criteria = new ArrayList<>();

if(name != null && !name.trim().isEmpty()) {
  criteria.add(cb.like(cb.upper(c.get(Customer_.firstName)), name));
}
if(surname != null && !surname.trim().isEmpty()) {
  criteria.add(cb.like(cb.upper(c.get(Customer_.lastName)), surname));
}

if(username != null && !username.trim().isEmpty()) {
  criteria.add(cb.like(cb.upper(c.get(Customer_.userId)), username));
}
if (criteria.size() == 0) {
  throw new ValidationException("search criteria not provided");
}
else if (criteria.size() == 1) {
  c.where(criteria.get(0));
}
else {
  c.where(cb.and(criteria.toArray(new Predicate[0])));
}
return em.createQuery(q).setMaxResults(10).getResultList();

但是调试 SQL 查询我可以看到限制应用于外部查询,即根据我的理解,首先获取所有结果然后从第一个结果中选择前 10 个。这看起来效率很低。

org.hibernate.SQL : 
  select * from (
    select distinct
      customer0_.part_id as part_id1_9_,
      customer0_.ref_no as ref_no2_9_,
      customer0_.name as name3_9_,
      customer0_.fiscal_code as fiscal_code4_9_,
      customer0_.surname as surname5_9_,
      customer0_.prod_type as prod_type6_9_,
      customer0_.role as role7_9_,
      customer0_.userid as userid8_9_
    from vw_gdpr_cust_data customer0_
    where (upper(customer0_.name) like ?)
  )
  where rownum <= ?
o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [VARCHAR] - [%ISM%]

有人可以解释一下,如何有效地实施行限制。

在 Oracle DB 版本 11g 和更早的版本中,为了限制结果(Top-N 查询),查询应该具有外部派生的 table 和 ROWNUM。需要外部派生 table 进行排序 (ORDER BY) 或在 ROWNUM.

之前应用 DISTINCT

以下查询有错误:

select * 
from emp 
where ROWNUM <= 5 
order by sal desc;

此查询的正确版本:

select * 
from ( select * from emp 
       order by sal desc ) 
where ROWNUM <= 5;

https://blogs.oracle.com/oraclemagazine/on-rownum-and-limiting-results

JPA setFirstResult(offset) 还需要外部派生查询:

select * 
from ( select * 
       from ( select * from emp 
              order by sal desc ) 
       where ROWNUM <= 8 ) /* last result */
where ROWNUM >= 5; /* first result */

在 Oracle 12c 中引入了 Top-N 和分页查询的新语法:

select * 
from emp 
order by sal desc
offset 4 rows fetch next 4 rows only;

考虑使用 org.hibernate.dialect.Oracle12cDialect