Mysql 使用连接缓冲区进行极慢的连接

Mysql 使用连接缓冲区进行极慢的连接,mysql,sql,hibernate,Mysql,Sql,Hibernate,我在使用多个联接的复杂查询时遇到问题。运行“解释”时: 查询 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.

我在使用多个联接的复杂查询时遇到问题。运行“解释”时:

查询

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"
数据模型如下所示:

帐户场馆活动宾客名单门票 UserDetail有一个帐户、地点、事件或来宾列表作为父项

我试图用这个查询来获取所有的UserDetail,这些UserDetail有一个特定的帐户/地点/事件/来宾列表作为父项,或者有一个来宾列表作为父项,其票证的reference_user字段设置为特定的用户

休眠条件

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();
}
公共列表listUserDetails(最终集合任意节点、最终用户orTicketReferenceUser、最终集合和任何用户列表ForticketReferenceUser、最终集合任意用户、最终日期自LastModificationDate、最终日期至LastModificationDate、最终布尔删除节点、最终布尔删除节点、最终布尔删除数据细节){
最终CriteriaBuilder cb=entityManager.getCriteriaBuilder();
最终标准查询cq=cb.createQuery(UserDetail.class);
最终根userDetail=cq.from(userDetail.class);
谓词条件=cb.conjunction();
if(任意节点!=null | | orTicketReferenceUser!=null){
谓词次标准=cb.disjunction();
if(任意节点!=null){
谓词anyOfNodeCriteria=cb.disconction();
集合计数=null;
集合anyof=null;
集合anyOfEvents=null;
集合anyofguestlist=null;
final Set anyOfNodesWithParents=新HashSet();
for(UserDetailNode节点:任意节点){
while(节点!=null){
添加(节点);
node=node.getParentNode();
}
}
for(最终UserDetailNode节点:anyOfNodeWithParents){
if(帐户的节点实例){
如果(anyOfAccounts==null)anyOfAccounts=new ArrayList();
anyOfAccounts.add((账户)节点);
}
else if(场地的节点实例){
如果(anyOfVinces==null)anyOfVinces=newArrayList();
添加((场馆)节点);
}
else if(事件的节点实例){
如果(anyOfEvents==null)anyOfEvents=new ArrayList();
添加((事件)节点);
}
else if(GuestList的节点实例){
如果(anyOfGuestList==null)anyOfGuestList=newArrayList();
添加((来宾列表)节点);
}
}
如果(anyOfAccounts!=null)anyOfNodesCriteria=cb.或(anyOfNodesCriteria,cb.或(anyOfAccounts)中的(userDetail.get(“account”);
如果(anyofvices!=null)anyOfNodesCriteria=cb.or(anyOfNodesCriteria,cb.or(userDetail.get(“场馆”).in(anyofvices));
如果(anyOfEvents!=null)anyOfNodesCriteria=cb.or(anyOfNodesCriteria,cb.or(userDetail.get(“事件”).in(anyOfEvents));
如果(anyofguestlist!=null)anyOfNodesCriteria=cb.or(anyOfNodesCriteria,cb.or(userDetail.get(“guestList”).in(anyofguestlist));
次标准=cb.或(次标准,任何标准);
}
if(orTicketReferenceUser!=null&(andAnyOfGuestlistsForTicketReferenceUser==null | |!andAnyOfGuestlistsForTicketReferenceUser.isEmpty()){
最终根票证=cq.from(票证类别);
谓词ticketCriteria=cb.equal(ticket.get(“referenceUser”)、orTicketReferenceUser);
ticketCriteria=cb.and(ticketCriteria,cb.or(cb.equal(userDetail.get(“guestList”)、ticket.get(“事件”)、ticket.get(“guestList”)、ticket.equal(userDetail.get(“场馆”)、ticket.get(“宾客列表”)、cb.equal(userDetail.get(“账户”)、ticket.get(“宾客列表”).get(“事件”)、get(“事件”).get(“事件”).get(“地点”)。获取(“账户”);
如果(andAnyOfGuestlistsForTicketReferenceUser!=null)ticketCriteria=cb.和(ticketCriteria,ticket.get(“来宾列表”).in(andAnyOfGuestlistsForTicketReferenceUser));
次标准=cb.或(次标准、票证标准);
}
标准=cb.和(标准,次标准);
}
if(任意用户!=null){
if(anyOfUsers.isEmpty())返回新的ArrayList();
criteria=cb.and(criteria,userDetail.get(“user”).in(anyofuser));
}
如果(fromLastModificationDate!=null)条件=cb.and(条件,cb.greaterThanOrEqualTo(userDetail.get(“lastModificationDate”),fromLastModificationDate));
如果(toLastModificationDate!=null)条件=cb.and(条件,cb.lessThanOrEqualTo(userDetail.get(“lastModificationDate”),toLastModificationDate));
选择(userDetail).distinct(true).where(条件);
返回entityManager.createQuery(cq.getResultList();
}

从我所看到的最后一行是问题所在,但是我如何解决这个问题呢?这个查询是由hibernate自动生成的,所以我不确定我可以对它进行多少修改。

您过度使用交叉连接笛卡尔连接没有意义……您实际上在寻找什么。因为您的“或”子句都基于这个值10,但是随后通过guest\u list id隐式地连接到ticket表——最后要求t.guest\u list=10

因为您的所有内部联接也在查看原始用户详细信息表,该表的值与联接的结果相同。你的关键是,最终的“和”是专门寻找客人名单=10。我会立即以此为基础,或其他。。。我可以考虑如下:

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\u User=10”,但上下文是什么。。。这是否像一个用户有一个客人?并且该客人可以与相同的用户详细信息事件/地点/acco关联