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
。
我要求一次最多 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
。