JPQL 또는 HQL에서 제한 쿼리를 어떻게 수행합니까?


239

최대 절전 모드 3에서는 HQL에서 다음과 같은 MySQL 제한을 수행하는 방법이 있습니까?

select * from a_table order by a_table_column desc limit 0, 20;

가능한 경우 setMaxResults를 사용하고 싶지 않습니다. 이것은 이전 버전의 Hibernate / HQL에서 가능했지만 사라진 것 같습니다.


2
사용하고 Hibernate-5.0.12있습니다. 여전히 사용할 수 없습니까? setMaxResults@skaffman의 답변에서 @Rachel에 의해 알 수 있듯이 백만 개 정도의 레코드를 얻은 다음 필터를 적용하는 것이 실제로 무겁 습니다.
Rajeev Ranjan

답변:


313

이것은 왜 Hibernate 2에서는 작동했지만 Hibernate 3에서는 작동하지 않는지에 대해 물었을 때 Hibernate 포럼 에 게시 되었습니다.

HQL에서는 제한이 지원되는 조항 이 아닙니다 . setMaxResults ()를 사용해야합니다.

따라서 최대 절전 모드 2에서 작동하면 디자인이 아니라 우연의 일치 인 것 같습니다. 내가 생각하는 일부 네이티브 SQL에 몰래 수 있도록 최대 절전 모드 2 HQL 파서, 그것은 HQL로 인식하는 쿼리의 비트를 교체하고 그것이로 나머지를 떠날 것 때문이었다. 그러나 최대 절전 모드 3에는 적절한 AST HQL 파서가 있으며 훨씬 덜 용서합니다.

Query.setMaxResults()정말 유일한 옵션 이라고 생각 합니다.


3
Hibernate 3의 접근 방식이 더 정확하다고 주장합니다. Hibernate를 사용하는 것은 데이터베이스에 구애받지 않기위한 것이므로 이러한 방식으로 추상적 인 방식으로 수행해야합니다.
matt b

6
나는 동의하지만 기능이 그렇게 떨어지면 엉덩이에 마이그레이션이 왕성하게됩니다.
skaffman

52
그러나 setMaxResults를 사용하면 첫 번째 쿼리가 실행 된 다음 결과 집합 setMaxResults에서 결과 집합에서 제한된 수의 결과 행을 가져 와서 사용자에게 표시합니다. 제 경우에는 3 백만 개의 레코드가 쿼리되고 setMaxResults를 호출하여 설정합니다. 50 개 레코드이지만 그렇게하고 싶지는 않지만 쿼리 자체는 50 개 레코드를 쿼리하려고하지만 그렇게하는 방법이 있습니까?
Rachel

2
내가 알고있는 오래된 포스트. 나는 Rachel에게 전적으로 동의합니다. NHibernate (. Hibernate의 .Net 포트)를 사용하여 최근에 2에서 3으로 업그레이드했으며 동일한 X, 이제 X가 파서 오류를 발생시킵니다. 그러나 쿼리에 setMaxResults를 추가하면 결과 SQL에서 MsSql2008Dialect를 사용하여 TOP X를 생성했습니다. 이거 좋다
Thierry_S

17
setMaxResults최대 절전 모드를 갖춘 @Rachel limit은 쿼리에 해당 부분을 추가합니다 . 모든 결과를 얻지는 못할 것입니다. 다음을 활성화하여 생성 한 쿼리를 확인할 수 있습니다.<property name="show_sql">true</property>
Andrejs

148
 // SQL: SELECT * FROM table LIMIT start, maxRows;

Query q = session.createQuery("FROM table");
q.setFirstResult(start);
q.setMaxResults(maxRows);

6
나는 setFirstResult이 답변에서 실제로 언급 되었기 때문에 가장 좋아 하는 반면 여기와 다른 곳 에서는 오프셋을 설정하는 방법을 언급하지 않고 setMaxResults이것을 말합니다 setMaxResults.
demongolem

19

사용하지 않으려면 setMaxResults()상의 Query객체 다음 수 정상적인 SQL을 사용하여 항상 되돌리기 다시.


37
그다지 흥미 진진한 것은 아닙니다.
stevedbrown

8
HQL도 흥미롭지 않습니다. DB 서버에 제한을 적용하는 뷰를 작성한 다음 HQL이 해당 뷰를 보도록하십시오 .P
pjp

1
SQL은 각 쿼리마다 HQL보다 훨씬 쉬운 반면 뷰를 생성하고 네이티브 SQL을 작성하는 것은 리팩토링에 적합하지 않은 경향이 있습니다. 할 수있을 때 피하려고 노력합니다. 실제로 실제 문제는 MySQL 쿼리를 잘못 작성하고 setMaxResults가 이상하다고 생각했다는 것입니다. 아니었다.
stevedbrown

다른 DBMS 공급 업체간에 전환하려고하면 고통이 기다리고 있습니다.
Olgun Kaya

5

setMaxResults를 사용하지 않으려면 list 대신 Query.scroll을 사용하여 원하는 행을 가져올 수 있습니다. 예를 들어 페이징에 유용합니다.


고마워, 받아 들인 대답은 setMaxResults()메모리에있는 모든 레코드를 먼저로드 한 다음 하위 목록을 생성하기 때문에 메모리가 부족하여 서버에 충돌하는 수십만 이상의 레코드가 있기 때문에 문제가 해결되지 않았습니다 . 그러나 JPA 유형 쿼리에서 최대 절전 모드 쿼리 로 이동할 수 있으며 제안한대로 메소드를 QueryImpl hibernateQuery = query.unwrap(QueryImpl.class)사용할 수 있습니다 scroll().
toongeorges

적어도 Oracle 방언의 경우 이것은 사실이 아닙니다 (Hibernate는 ROWNUM 가상 열을 사용합니다). 드라이버에 따라 다를 수 있습니다. 다른 DB에는 TOP 기능이 있습니다.
Lluis Martinez

내 쿼리가 조인 페치를 사용하고 있습니다. 이로 인해 최대 절전 모드 경고 "컬렉션 페치로 지정된 firstResult / maxResults; 메모리에 적용"이 발생합니다. 따라서 조인 페치를 사용하면 Hibernate는 전체 컬렉션을 메모리에로드합니다. 성능상의 이유로 조인을 삭제하는 것은 옵션이 아닙니다. ScrollableResults를 사용하면 메모리에로드되는 레코드에 대한 제어가 강화됩니다. 하나의 ScrollableResults를 사용하여 모든 레코드를로드 할 수는 없습니다. 메모리가 부족하기 때문입니다. 다른 ScrollableResults로 여러 페이지를로드하는 것을 실험하고 있습니다. 이것이 작동하지 않으면 SQL을 사용합니다.
toongeorges 2016 년

이상하다, 나는 결코 그런 적이 없다. 그렇습니다. 특히 대량 / 배치 프로세스의 경우 직선 JDBC를 사용하는 것이 좋습니다.
Lluis Martinez

@OneToMany 관계로 인해 문제가 발생합니다. 어떻게 든 다중 값을 단일 값으로 연결하기 위해 Hibernate에서 Oracle 집계 함수 LISTAGG를 실행할 수 있다면 조인을 삭제하고 하위 쿼리로 대체 할 수 있습니다.
toongeorges 2016 년

2

이를 위해 페이지 매김을 쉽게 사용할 수 있습니다.

    @QueryHints({ @QueryHint(name = "org.hibernate.cacheable", value = "true") })
    @Query("select * from a_table order by a_table_column desc")
    List<String> getStringValue(Pageable pageable);

new PageRequest(0, 1)레코드를 가져오고 목록에서 첫 번째 레코드 를 가져 오려면 전달해야 합니다 .


2

이것은 매우 일반적인 질문 이므로이 답변을 기반으로하는이 기사를 작성 했습니다.

setFirstResultsetMaxResults Query방법

JPA 및 Hibernate의 Query경우, setFirstResult메소드 는와 동일 OFFSET하며 setMaxResults메소드는 LIMIT와 같습니다.

List<Post> posts = entityManager
.createQuery(
    "select p " +
    "from Post p " +
    "order by p.createdOn ")
.setFirstResult(10)
.setMaxResults(10)
.getResultList();

LimitHandler추상화

Hibernate LimitHandler는 데이터베이스 특정 페이지 매김 로직을 정의하고, 다음 다이어그램에서 보여 지듯이, 많은 데이터베이스 특정 페이지 매김 옵션을 지원합니다.

<code> LimitHandler </ code> 구현

이제 사용중인 기본 관계형 데이터베이스 시스템에 따라 위의 JPQL 쿼리는 적절한 페이지 매김 구문을 사용합니다.

MySQL

SELECT p.id AS id1_0_,
       p.created_on AS created_2_0_,
       p.title AS title3_0_
FROM post p
ORDER BY p.created_on
LIMIT ?, ?

PostgreSQL

SELECT p.id AS id1_0_,
       p.created_on AS created_2_0_,
       p.title AS title3_0_
FROM post p
ORDER BY p.created_on
LIMIT ?
OFFSET ?

SQL 서버

SELECT p.id AS id1_0_,
       p.created_on AS created_on2_0_,
       p.title AS title3_0_
FROM post p
ORDER BY p.created_on
OFFSET ? ROWS 
FETCH NEXT ? ROWS ONLY

신탁

SELECT *
FROM (
    SELECT 
        row_.*, rownum rownum_
    FROM (
        SELECT 
            p.id AS id1_0_,
            p.created_on AS created_on2_0_,
            p.title AS title3_0_
        FROM post p
        ORDER BY p.created_on
    ) row_
    WHERE rownum <= ?
)
WHERE rownum_ > ?

사용의 장점 setFirstResultsetMaxResults최대 절전 모드가 지원되는 관계형 데이터베이스에 대한 데이터베이스 특정 페이지 매김 구문을 생성 할 수 있다는 것입니다.

또한 JPQL 쿼리에만 국한되지 않습니다. 네이티브 SQL 쿼리에 setFirstResultand 및 setMaxResultsmethod 7을 사용할 수 있습니다 .

기본 SQL 쿼리

기본 SQL 쿼리를 사용할 때 데이터베이스 별 페이지 매김을 하드 코딩 할 필요가 없습니다. 최대 절전 모드로 쿼리에 추가 할 수 있습니다.

따라서 PostgreSQL에서이 SQL 쿼리를 실행하는 경우 :

List<Tuple> posts = entityManager
.createNativeQuery(
    "SELECT " +
    "   p.id AS id, " +
    "   p.title AS title " +
    "from post p " +
    "ORDER BY p.created_on", Tuple.class)
.setFirstResult(10)
.setMaxResults(10)
.getResultList();

최대 절전 모드는 다음과 같이 변환합니다.

SELECT p.id AS id,
       p.title AS title
FROM post p
ORDER BY p.created_on
LIMIT ?
OFFSET ?

멋지죠?

SQL 기반 페이지 매김을 넘어

페이지 매김은 필터링 및 정렬 기준을 색인 할 수있을 때 좋습니다. 페이지 매김 요구 사항이 동적 필터링을 의미하는 경우 ElasticSearch와 같은 역 인덱스 솔루션을 사용하는 것이 훨씬 좋습니다.

확인 이 문서 자세한 내용을.


1

String hql = "select userName from AccountInfo order by points desc 5";

이것은 사용하지 않고 나를 위해 일했습니다. setmaxResults();

keyword를 사용하지 않고 마지막 값 (이 경우 5)에 최대 값을 제공하십시오 limit. :피


7
흠 ... 이것에 대해 너무 잘 모르겠습니다. [인용이 필요했습니다] 이것은 사고 일 수 있으며 새로운 버전의 최대 절전 모드에서 갑자기 작동을 멈출 수 있습니다.
Konrad 'ktoso'Malawski

4
공식 문서를 참조하십시오.
Nhu Vy

1
이것은 Hibernate Version 5.2.12 Final에서 작동하지 않습니다.
jDub9

1
작동하지 않습니다. 최대 절전 모드 4.x도 지원하지 않습니다.
Faiz Akram

0

내 관찰에 따르면 HQL (최대 절전 모드 3.x)에 제한이 있어도 구문 분석 오류가 발생하거나 무시됩니다. (한계 전에 + desc / asc로 주문한 경우 무시됩니다. 한도 전에 desc / asc가 없으면 파싱 오류가 발생합니다)


0

이 모드에서 한도를 관리 할 수있는 경우

public List<ExampleModel> listExampleModel() {
    return listExampleModel(null, null);
}

public List<ExampleModel> listExampleModel(Integer first, Integer count) {
    Query tmp = getSession().createQuery("from ExampleModel");

    if (first != null)
        tmp.setFirstResult(first);
    if (count != null)
        tmp.setMaxResults(count);

    return (List<ExampleModel>)tmp.list();
}

이것은 제한 또는 목록을 처리하는 정말 간단한 코드입니다.


0
Criteria criteria=curdSession.createCriteria(DTOCLASS.class).addOrder(Order.desc("feild_name"));
                criteria.setMaxResults(3);
                List<DTOCLASS> users = (List<DTOCLASS>) criteria.list();
for (DTOCLASS user : users) {
                System.out.println(user.getStart());
            }

0

네이티브 쿼리를 작성해야합니다 ( 참조) .

@Query(value =
    "SELECT * FROM user_metric UM WHERE UM.user_id = :userId AND UM.metric_id = :metricId LIMIT :limit", nativeQuery = true)
List<UserMetricValue> findTopNByUserIdAndMetricId(
    @Param("userId") String userId, @Param("metricId") Long metricId,
    @Param("limit") int limit);

0

아래 쿼리를 사용할 수 있습니다

NativeQuery<Object[]> query = session.createNativeQuery(select * from employee limit ?)
query.setparameter(1,1);

0

아래 스 니펫은 HQL을 사용하여 제한 쿼리를 수행하는 데 사용됩니다.

Query query = session.createQuery("....");
query.setFirstResult(startPosition);
query.setMaxResults(maxRows);

링크 에서 데모 응용 프로그램을 얻을 수 있습니다 .


-1
@Query(nativeQuery = true,
       value = "select from otp u where u.email =:email order by u.dateTime desc limit 1")
public List<otp> findOtp(@Param("email") String email);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.