2012-01-09 3 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- > GuestList < 1-> Ticket UserDetail имеет учетную запись, место проведения, событие или список гостей в качестве родителя.

И что я пытаюсь сделать с этим запросом, это получить все UserDetail, у которого есть один из определенных учетных записей/место/событие/guestlist в качестве родителя, OR, у которого есть список гостей как родитель, у которого есть билет который имеет поле 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, и, наконец, ТРЕБУЕТСЯ t.guest_list = 10?

Поскольку все ваши внутренние соединения ТАКЖЕ относятся к исходной таблице подробностей пользователя, имеющей то же значение, что и результат объединения. Ваш кикер, что FINAL «И» специально ищет 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», но что это за контекст ... это то, что, как и у одной детали пользователя, есть гость? и что гость может быть связан с одним и тем же подробным событием/местом/аккаунтом пользователя?

Предоставляя некоторые образцы деталей, и разъяснение того, что вы надеетесь получить получит Вас намного дальше вперед ...

+0

DRapp, пожалуйста, проверьте мой вопрос еще раз - я добавил дополнительную информацию. Сам запрос генерируется Hibernate, поэтому он не был личным выбором. Является ли порядок критериев важным? –

+0

@PiotrBlasiak, извините за задержку ... Не видя фактических данных и лучшего контекста для отношений, я не думаю, что могу предложить вам гораздо больше. – DRapp

Смежные вопросы