2008-10-14 4 views
45

최대 절전 모드를 사용하여 통합 쿼리를 구현해야하는 다른 방법은 무엇입니까? 저는 현재 최대 절전 모드가 노동 조합 쿼리를 지원하지 않는다는 것을 알고 있습니다. 지금은 노동 조합을 만드는 유일한 방법은 뷰 테이블을 사용하는 것입니다.Hibernate Union 대안

다른 옵션은 plain jdbc를 사용하는 것입니다. 그러나이 방법을 사용하면 최대 절전 모드가 테이블/열에 대해 수행하는 최대 절전 모드 매핑 유효성 검사와 마찬가지로 모든 예제/조건 쿼리를 느슨하게 할 수 있습니다.

+2

하나는 집계 개체를 사용하는 것입니다, http://stackoverflow.com/questions/ 7322526/hibernate-jpa-it-possible-to-retrieve-heterogeneous-entities-in-a-single-que/7322738 # 7322738). –

답변

22

보기를 사용하십시오. 엔티티 이름을 사용하여 동일한 클래스를 다른 테이블/뷰에 매핑 할 수 있으므로 복제본이 많지 않습니다. 거기에있어, 해냈어. 좋아.

일반 JDBC는 Hibernate 세션 캐시를 인식하지 못하기 때문에 트랜잭션의 끝까지 캐시되고 Hibernate 세션에서 플러시되지 않으면 JDBC 쿼리에서 찾지 못한다. 때로는 매우 혼란 스러울 수 있습니다.

+2

그리고 두 번째 수준의 캐시가있을 때 더 혼란 스럽지만 응용 프로그램의 다른 부분에서 일반 JDBC를 사용합니다 (보고 용으로). – javashlook

5

블라디미르에 동의해야합니다. 나도 HQL에서 UNION을 사용하여 살펴 보았고 그 주위에 방법을 찾을 수 없었다. 이상한 점은 UNION이 지원되지 않는다는 것을 (Hibernate FAQ에서) 발견 할 수 있었고, UNION에 관련된 버그 리포트가 'fixed'라고 표시된 사람들, UNION에서 선언문이 잘 리거나 다른 뉴스 그룹이 작동한다고 말하는 사람들의 뉴스 그룹이었습니다. 괜찮아 ... 하루를 마친 후에도 HQL을 일반 SQL로 다시 포팅했지만 결국 데이터베이스에서 View로 수행하면 좋은 옵션이 될 것입니다. 필자의 경우 쿼리의 일부가 동적으로 생성되었으므로 코드 대신 SQL을 작성해야했습니다.

+1

발견 한 다양한 이론과 올바른 이론을 열거 해 주셔서 감사합니다. "합리적인 개발자"가 기대할 수있는 것과 다른 점은 차이점은 가장 유용한 메모 중 일부입니다. –

3

보기가 더 나은 방법이지만 일반적으로 hql은 List 또는 Set ...을 반환하기 때문에 list_1.addAll (list_2)을 사용할 수 있습니다. 노조에 비해 완전히 짜증나지만 작동해야합니다.

0

나는이 고통을 겪었습니다. 쿼리가 동적으로 생성 된 경우 (예 : 최대 절전 기준) 그런 다음 실용적인 방법으로 찾을 수 없습니다.

필자에게 좋은 소식은 오라클 데이터베이스에서 '또는'을 사용할 때 성능 문제를 해결하기 위해 노조를 조사하는 것이 었습니다.

패트릭 (Patrick)이 게시 한 솔루션은 프로그래밍 방식으로 세트를 사용하여 결과를 결합한 반면 추한 (특히 결과 페이징을 수행하고 싶었 기 때문에) 솔루션으로는 충분했습니다.

2

아마도 나는 더 솔직하게 해결해야 할 문제가있었습니다. 내 '예를 들어'JPA 공급자와 같은 최대 절전 모드 JPA에있었습니다.

세 개의 선택 (두 번째 경우에는 두 개)을 여러 개의 선택으로 나누고 컬렉션을 결합하여 효과적으로 '전체'를 대체합니다.

+2

이 방법은 효과가 있지만 그다지 효과적이지 않습니다. –

54

id in (select id from ...) or id in (select id from ...)

대신 당신은 적어도 MySQL을 사용

from Person p 
    where p.id in (select p1.id from Person p1 where p1.name="Joe") 
    or p.id in (select p2.id from Person p2 join p2.children c where c.name="Joe"); 

을 할 수

from Person p where p.name="Joe" 
union 
from Person p join p.children c where c.name="Joe" 

비 작동, 당신은하지만, 나중에와 성능 문제로 실행됩니다. 종종 두 개의 쿼리에 대해 가난한 사람이 참여하는 것이 더 쉽습니다.

// use set for uniqueness 
Set<Person> people = new HashSet<Person>((List<Person>) query1.list()); 
people.addAll((List<Person>) query2.list()); 
return new ArrayList<Person>(people); 

하나의 복합 쿼리보다 두 번의 간단한 쿼리를 수행하는 것이 더 나을 때가 있습니다.

편집 :

는 예를주고, 여기가 부속 솔루션에서 결과 MySQL의 쿼리의 출력을 EXPLAIN입니다 :

mysql> explain 
    select p.* from PERSON p 
    where p.id in (select p1.id from PERSON p1 where p1.name = "Joe") 
     or p.id in (select p2.id from PERSON p2 
     join CHILDREN c on p2.id = c.parent where c.name="Joe") \G 
*************************** 1. row *************************** 
      id: 1 
    select_type: PRIMARY 
     table: a 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 247554 
     Extra: Using where 
*************************** 2. row *************************** 
      id: 3 
    select_type: DEPENDENT SUBQUERY 
     table: NULL 
     type: NULL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: NULL 
     Extra: Impossible WHERE noticed after reading const tables 
*************************** 3. row *************************** 
      id: 2 
    select_type: DEPENDENT SUBQUERY 
     table: a1 
     type: unique_subquery 
possible_keys: PRIMARY,name,sortname 
      key: PRIMARY 
     key_len: 4 
      ref: func 
     rows: 1 
     Extra: Using where 
3 rows in set (0.00 sec) 

가 가장 중요한 1 행이 어떤 인덱스를 사용하지 않고, 200k + 행을 고려합니다. 나쁜! 이 쿼리를 실행하면 0.7 초가 걸리므로 두 하위 쿼리 모두 밀리 초 안에 있습니다.

4

저는 HQL에서 하나의 중요한 시나리오 (제가 많이 고심 해 왔던)에 대한 해결책을 가지고 있습니다.

대신 작동하지의 : -

select i , j from A a , (select i , j from B union select i , j from C) d where a.i = d.i 

또는

select i , j from A a JOIN (select i , j from B union select i , j from C) d on a.i = d.i 

당신은 최대 절전 모드 HQL에서 할 수있는 ->

Query q1 =session.createQuery(select i , j from A a JOIN B b on a.i = b.i) 
List l1 = q1.list(); 

Query q2 = session.createQuery(select i , j from A a JOIN C b on a.i = b.i) 
List l2 = q2.list(); 

다음 U가 모두 목록에 추가 할 수 있습니다 ->

l1.addAll(l2); 
+1

노동 조합은 데이터베이스에 의해 수행되지 않고 진행 중이며 Walt의 제안과 동일합니다. –

+0

그래서 여기에서 정렬하려면 어떻게해야합니까? 다른 병합 알고리즘을 구현하여 정렬 메커니즘을 복제하게 될 수도 있습니다. 아주 좋지 않다. – Bondax

0



패트릭 좋은 생각을 할 수 있지만 UNION ALL 같은 역할을 기억 것을 선택 각에서 LIST에게의를 추가, 말했듯이. 이 부작용을 피하려면 오브젝트가 이미 최종 콜렉션에 추가되었는지 여부 만 제어하십시오. 아니요 인 경우 추가하십시오. 당신에 대해 관심을 가져야 다른
뭔가 당신이 가지고있는 경우 이 결과는 객체 배열 (List<Objetc[]>)의 목록이 될 것을 선택 가입이다 그래서 당신은 단지 객체를 유지에 반복해야 너는 필요해.

희망 사항.

0

여기는 특별한 경우이지만 자신 만의 작품을 만들 수있는 영감을 줄 수 있습니다. 목표는 레코드가 특정 기준을 충족시키는 두 개의 다른 테이블에서 레코드의 총 수를 세는 것입니다. 이 기술은 여러 테이블/소스에서 데이터를 집계해야하는 모든 경우에 사용할 수 있다고 생각합니다.

특수 중간 클래스 설정이 있으므로 명명 된 쿼리를 호출하는 코드는 짧고 빠르지 만 일반적으로 명명 된 쿼리와 함께 사용하는 방법을 사용하여 쿼리를 실행할 수 있습니다.

@Entity 
@NamedQueries({ 
     @NamedQuery(
      name ="PIXEL_ALL", 
      query = "" + 
        " SELECT new SourceCount(" + 
        "  (select count(a) from PIXEL_LOG_CURR1 a " + 
        "  where to_char(a.TIMESTAMP, 'YYYYMMDD') = :PROCDATE " + 
        " )," + 
        "  (select count(b) from PIXEL_LOG_CURR2 b" + 
        "  where to_char(b.TIMESTAMP, 'YYYYMMDD') = :PROCDATE " + 
        " )" + 
        ") from Dual1" + 
        "" 
    ) 
}) 

public class SourceCount { 
    @Id 
    private Long COUNT; 

    public SourceCount(Long COUNT1, Long COUNT2) { 
     this.COUNT = COUNT1+COUNT2; 
    } 

    public Long getCOUNT() { 
     return COUNT; 
    } 

    public void setCOUNT(Long COUNT) { 
     this.COUNT = COUNT; 
    } 
} 

여기에 마법의 일부는 더미 테이블을 만들고으로 하나 개의 레코드를 삽입하는 것입니다 : 당신이 여기에서 볼 수 있듯이

QueryParms parms=new QueryParms(); 
parms.put("PROCDATE",PROCDATE); 

Long pixelAll = ((SourceCount)Fetch.row("PIXEL_ALL",parms,logger)).getCOUNT(); 

, 명명 된 쿼리는 노동 조합 문 같은 aweful 많이 찾기 시작합니다 그것. 필자의 경우 데이타베이스가 오라클이기 때문에 이름을 dual1로 지정했지만 더미 테이블이라고 부르는 것이 중요하지는 않습니다.

@Entity 
@Table(name="DUAL1") 
public class Dual1 { 
    @Id 
    Long ID; 
} 

이 더미 레코드를 삽입하는 것을 잊지 마세요 : [여기] 설명 (솔루션의

SQL> insert into dual1 values (1);