SpringData и Querydsl генерируют неоптимальный запрос

Я использую JPA (Hibernate v4.1.7), Spring Data (v1.4.1) и Query DSL (v3.2.3) для построения моего уровня DAO в базе данных Postgres.

Но сгенерированный SQL для запросов не оптимален для фильтрации по отношению @ElementCollection (аналогичная проблема существует с отношением @OneToMany)

У меня есть сущность:

@Entity
@Table(name = "doc_documents")
public class Document {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ElementCollection(fetch = FetchType.LAZY)
    @CollectionTable(name = "doc_document_titles",
        joinColumns =
        @JoinColumn(name = "document_id"))
    @Column(name = "title")
    private List<String> titles = new ArrayList<>();
….
)

И интерфейс репозитория:

public interface DocumentRepo
        extends JpaRepository <Document, Long>, 
                QueryDslPredicateExecutor<Document> {
}

Когда я выполняю свой запрос:

Predicate crit = qDoc.titles.any().eq("x");
docRepo.findAll(crit);

Этот SQL выполняется:

select
    document0_.id as id10_
from
    doc_documents document0_ 
where
    exists (
        select
            1 
        from
            doc_documents document1_ 
        inner join
            doc_titles title2_ 
                on document1_.id= title2_.document_id 
        where
            document1_.id=document0_.id 
            and locthesaur2_.title = ?
    )

Но я думаю, что оптимальный SQL для этого запроса должен быть без дополнительного внутреннего соединения:

select
    document0_.id as id10_
from
    doc_documents document0_ 
where
    exists (
        select
            1 
        from
            doc_titles title2_ 
        where
            title2_.document_id=document0_.id 
            and title2.title= ?
    )

Дополнительное внутреннее соединение серьезно портит производительность. Можно ли указать QueryDSL для генерации другого запроса, или, может быть, я просто делаю что-то не так?

Проблема производительности жизненно важна для моего приложения, поэтому без этой оптимизации я не могу использовать QueryDSL для запросов к базе данных (у меня гораздо более сложный домен, чем я показал здесь).


person Palladium    schedule 03.12.2013    source источник
comment
Какую версию Querydsl вы используете?   -  person Timo Westkämper    schedule 03.12.2013
comment
Версия QueryDsl — 3.2.3.   -  person Palladium    schedule 03.12.2013


Ответы (1)


Предикат внутренне переводится во что-то подобное на уровне JPQL.

exists (select 1 
        from Document doc2 
        inner join doc2.titles as doc2_titles
        where doc2 = doc and doc2_titles = ?)

Невозможно использовать заголовки непосредственно в части from, так как это не сущность. Дайте мне знать, если вы найдете лучший способ выразить это в JPQL.

Если есть аналогичная проблема для OneToMany, создайте для этого тикет.

person Timo Westkämper    schedule 03.12.2013