2012-01-09 9 views
0

複数の結合を持つ複雑なクエリに問題があります。実行している場合、EXPLAIN:結合バッファを使用した結合が非常に遅い

クエリ

explain 

select ud.id from user_detail ud 
cross join ticket t 
cross join guest_list gl 
cross join event e 
cross join venue v 

where t.guest_list = gl.id and gl.event = e.id and e.venue = v.id 
and (ud.account = 10 or ud.venue = 10 or ud.event = 10 or ud.guest_list = 10 or t.reference_user = 10 and (ud.guest_list=t.guest_list or ud.event = gl.event or ud.venue = e.venue or ud.account = v.account) and (t.guest_list = 10)) 

私はこれを取得:

id, select_type, table, type, rows, extra 
1, SIMPLE, v, index, 2, "Using index" 
1, SIMPLE, e, ref, 2, "Using where; using index" 
1, SIMPLE, gl, ref, 1, "Using where; using index" 
1, SIMPLE, t, ref, 418, "Using where" 
1, SIMPLE, ud, ALL, 44028, "Using where; Using join buffer" 

データモデルは、このようなものです:

アカウント<の1- >会場< 1->イベント< 1- ゲストリスト< 1->チケット UserDetailには、アカウント、会場、イベント、またはゲストリストが親としてあります。

そして、このクエリで何をしようとしているのは、特定のaccount/venue/event/guestlistのいずれかを親として持つすべてのUserDetailを取得することです。または、チケットを持つ親としてguestlistを持つ特定のユーザーにreference_userフィールドが設定されています。

Hibernateの基準

public List<UserDetail> listUserDetails(final Collection<UserDetailNode> anyOfNodes, final User orTicketReferenceUser, final Collection<GuestList> andAnyOfGuestlistsForTicketReferenceUser, final Collection<User> anyOfUsers, final Date fromLastModificationDate, final Date toLastModificationDate, final Boolean deletedNodes, final Boolean deletedUsers, final Boolean deletedUserDetails) { 

    final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); 
    final CriteriaQuery<UserDetail> cq = cb.createQuery(UserDetail.class); 
    final Root<UserDetail> userDetail = cq.from(UserDetail.class); 
    Predicate criteria = cb.conjunction(); 

    if (anyOfNodes != null || orTicketReferenceUser != null) { 

     Predicate subCriteria = cb.disjunction(); 

     if (anyOfNodes != null) { 

      Predicate anyOfNodesCriteria = cb.disjunction(); 

      Collection<Account> anyOfAccounts = null; 
      Collection<Venue> anyOfVenues = null; 
      Collection<Event> anyOfEvents = null; 
      Collection<GuestList> anyOfGuestLists = null; 

      final Set<UserDetailNode> anyOfNodesWithParents = new HashSet<UserDetailNode>(); 
      for (UserDetailNode node : anyOfNodes) { 

       while (node != null) { 

        anyOfNodesWithParents.add(node); 
        node = node.getParentNode(); 
       } 
      } 

      for (final UserDetailNode node : anyOfNodesWithParents) { 

       if (node instanceof Account) { 

        if (anyOfAccounts == null) anyOfAccounts = new ArrayList<Account>(); 
        anyOfAccounts.add((Account)node); 
       } 
       else if (node instanceof Venue) { 

        if (anyOfVenues == null) anyOfVenues = new ArrayList<Venue>(); 
        anyOfVenues.add((Venue)node); 
       } 
       else if (node instanceof Event) { 

        if (anyOfEvents == null) anyOfEvents = new ArrayList<Event>(); 
        anyOfEvents.add((Event)node); 
       } 
       else if (node instanceof GuestList) { 

        if (anyOfGuestLists == null) anyOfGuestLists = new ArrayList<GuestList>(); 
        anyOfGuestLists.add((GuestList)node); 
       } 
      } 

      if (anyOfAccounts != null) anyOfNodesCriteria = cb.or(anyOfNodesCriteria, cb.or(userDetail.get("account").in(anyOfAccounts))); 
      if (anyOfVenues != null) anyOfNodesCriteria = cb.or(anyOfNodesCriteria, cb.or(userDetail.get("venue").in(anyOfVenues))); 
      if (anyOfEvents != null) anyOfNodesCriteria = cb.or(anyOfNodesCriteria, cb.or(userDetail.get("event").in(anyOfEvents))); 
      if (anyOfGuestLists != null) anyOfNodesCriteria = cb.or(anyOfNodesCriteria, cb.or(userDetail.get("guestList").in(anyOfGuestLists))); 

      subCriteria = cb.or(subCriteria, anyOfNodesCriteria); 
     } 

     if (orTicketReferenceUser != null && (andAnyOfGuestlistsForTicketReferenceUser == null || !andAnyOfGuestlistsForTicketReferenceUser.isEmpty())) { 

      final Root<Ticket> ticket = cq.from(Ticket.class); 
      Predicate ticketCriteria = cb.equal(ticket.get("referenceUser"), orTicketReferenceUser); 
      ticketCriteria = cb.and(ticketCriteria, cb.or(cb.equal(userDetail.get("guestList"), ticket.get("guestList")), cb.equal(userDetail.get("event"), ticket.get("guestList").get("event")), cb.equal(userDetail.get("venue"), ticket.get("guestList").get("event").get("venue")), cb.equal(userDetail.get("account"), ticket.get("guestList").get("event").get("venue").get("account")))); 

      if (andAnyOfGuestlistsForTicketReferenceUser != null) ticketCriteria = cb.and(ticketCriteria, ticket.get("guestList").in(andAnyOfGuestlistsForTicketReferenceUser)); 

      subCriteria = cb.or(subCriteria, ticketCriteria); 
     } 

     criteria = cb.and(criteria, subCriteria); 
    } 

    if (anyOfUsers != null) { 

     if (anyOfUsers.isEmpty()) return new ArrayList<UserDetail>(); 
     criteria = cb.and(criteria, userDetail.get("user").in(anyOfUsers)); 
    } 

    if (fromLastModificationDate != null) criteria = cb.and(criteria, cb.greaterThanOrEqualTo(userDetail.<Date>get("lastModificationDate"), fromLastModificationDate)); 
    if (toLastModificationDate != null) criteria = cb.and(criteria, cb.lessThanOrEqualTo(userDetail.<Date>get("lastModificationDate"), toLastModificationDate)); 

    cq.select(userDetail).distinct(true).where(criteria); 

    return entityManager.createQuery(cq).getResultList(); 
} 

私は最後の行を見ることができるものからは問題ですが、私はこれをどのように修正することができますか?このクエリは自動でHibernateによって生成されるので、どのくらい私がそれを変更できるかわかりません。

+0

あなたがuser_detailテーブルの上にすべてのインデックスを持っているのですか? –

+0

はい、使用されているすべての列はインデックス付きキーまたは外部キーのいずれかです –

+0

なぜこれでクロス結合を使用していますか? – HLGEM

答えて

1

クロスジョインのデカルト結合の使用が意味をなさない...あなたが実際に探しているのは何ですか。あなたの "OR"句はすべてこの値10に基づいていますが、guest_list idによってチケットテーブルへの暗黙的な結合を行い、最後にt.guest_list = 10?

内部結合はすべて、結合の結果と同じ値を持つ元のユーザー詳細テーブルを参照しているためです。あなたのキッカーはFINAL「AND」、具体的guest_list = 10探している私はすぐに基礎として、これを起動し、OR他の人でしょうが...私は次のことを検討するかもしれないということです。

select STRAIGHT_JOIN 
     ud.id 
    from 
     ticket t 
     JOIN user_detail ud 
      ON t.guest_list = ud.guest_list 
    where 
      t.guest_list = 10 
     AND ( ud.account = 10 
      or ud.venue = 10 
      or ud.event = 10) 

あなたが言及して"Reference_User = 10"に設定しますが、そのコンテキストとは... 1つのユーザー詳細にゲストがいるようですか?そのゲストは同じユーザー詳細イベント/会場/アカウントに関連付けることができますか?詳細のいくつかのサンプルを提供することにより

、そしてあなたが得ることを望んでいるかの明確化がはるかにさらに先にあなたを取得します...

+0

DRapp、もう一度私の質問を確認してください - 私は詳細を追加しました。クエリ自体はHibernateによって生成されるため、個人的な選択ではありません。基準の順序は重要ですか? –

+0

@PiotrBlasiak、申し訳ありませんが遅れて...実際のデータを見ることなく、より良い関係の関係を見ることなく、私はあなたにもっと多くを提供できるとは思わない。 – DRapp