2012-01-31 99 views
1

我们在项目中经常使用Criteria进行动态查询生成。我真的很喜欢表达查询的方式。问题是我们发现这个特定的查询不能使用基于clientId的索引,所以我们需要改变它。这里是工作的非索引查询:我可以使用Hibernate的Criteria在from子句中生成子查询吗?

public List<EventInstance> getEventInstances(Date from, Date to, Integer clientId) { 
    Session session = this.getSession(); 

    Criteria criteria = session.createCriteria(EventInstance.class); 

    if(clientId != null){ 

     criteria.add(Restrictions.disjunction() 
      .add(Restrictions.eq("clientId", clientId)) 
      .add(Restrictions.eq("team1ClientId", clientId)) 
      .add(Restrictions.eq("team2ClientId", clientId)) 
      ); 
    } 

    if(from != null){ 
     criteria.add(Restrictions.ge("startTime", from)); 
    } 

    if(to != null){ 
     criteria.add(Restrictions.le("startTime", to)); 
    } 

    @SuppressWarnings("unchecked") 
    List<EventInstance> events = criteria.list(); 

    this.releaseSession(session); 
    return events; 
} 

这个查询只能使用开始时间指数,并且无法使用索引与任何ClientID的年代。我发现,查询以下形式有效地使用我们的索引,我要创建这个查询与标准:

select * from (select * from eventInstance where (clientId = 8 or team1ClientId = 8 or team2ClientId = 8)) evtalias where evtalias.startTime < now() 

我已经能够做一个子选择使用此代码的WHERE子句中:

public List<EventInstance> getEventInstances(Date from, Date to, Integer clientId){ 
    Session session = this.getSession(); 

    DetachedCriteria subSelectClient = DetachedCriteria.forClass(EventInstance.class); 
    if(clientId != null){ 
     subSelectClient.add(Restrictions.disjunction() 
      .add(Restrictions.eq("clientId", clientId)) 
      .add(Restrictions.eq("team1ClientId", clientId)) 
      .add(Restrictions.eq("team2ClientId", clientId)) 
      ) 
      .setProjection(Property.forName("id")); 
    } 


    Criteria criteria = session.createCriteria(EventInstance.class); 

    if(clientId != null){ 
     criteria.add(Property.forName("id").in(subSelectClient)); 
    } 

    if(from != null){ 
     criteria.add(Restrictions.ge("startTime", from)); 
    } 

    if(to != null){ 
     criteria.add(Restrictions.le("startTime", to)); 
    } 

    @SuppressWarnings("unchecked") 
    List<EventInstance> events = criteria.list(); 

    this.releaseSession(session); 
    return events; 
} 

这会产生这样的查询:

select * from eventInstance this_ where this_.id in (select this_.id as y0_ from eventInstance this_ where (this_.clientId=8 or this_.team1ClientId=8 or this_.team2ClientId=8)) and this_.startTime<=now(); 

这是在使用索引比我原来的查询更差,并且不会在子查询中。

所以我的问题是,我可以在条件中做到这一点,或者我坚持使用HQL甚至原生SQL。或者,如果你知道如何创建一个可以解决我的问题的索引,但是我从mysql文档中了解到这是不可能的。

这里是目标查询说明输出我要创建:

mysql> explain select * from (select * from eventInstance where (clientId = 8 or  team1ClientId = 8 or team2ClientId = 8)) evtalias where evtalias.startTime < now(); 
+----+-------------+---------------+-------------+-------------------------------+----- ------------------+---------+------+------+------------------------------------------------ --------------+ 
| id | select_type | table   | type  | possible_keys     | key     | key_len | ref | rows | Extra              | 
+----+-------------+---------------+-------------+-------------------------------+-----------------------+---------+------+------+--------------------------------------------------------------+ 
| 1 | PRIMARY  | <derived2> | ALL   | NULL       | NULL     | NULL | NULL | 288 | Using where             | 
| 2 | DERIVED  | eventInstance | index_merge | eijoin2,ei_client,team2,team1 | ei_client,team1,team2 | 5,5,5 | NULL | 300 | Using union(ei_client,team1,team2); Using where; Using index | 
+----+-------------+---------------+-------------+-------------------------------+-----------------------+---------+------+------+--------------------------------------------------------------+ 
2 rows in set (0.00 sec) 

这是从休眠状态的标准子查询解释:据我所知

+----+--------------------+-------+-----------------+---------------------------------------+---------+---------+------+-------+-------------+ 
| id | select_type  | table | type   | possible_keys       | key  | key_len | ref | rows | Extra  | 
+----+--------------------+-------+-----------------+---------------------------------------+---------+---------+------+-------+-------------+ 
| 1 | PRIMARY   | this_ | ALL    | ei3         | NULL | NULL | NULL | 49434 | Using where | 
| 2 | DEPENDENT SUBQUERY | this_ | unique_subquery | PRIMARY,eijoin2,ei_client,team2,team1 | PRIMARY | 4  | func |  1 | Using where | 
+----+--------------------+-------+-----------------+---------------------------------------+---------+---------+------+-------+-------------+ 
2 rows in set (0.00 sec) 

回答

3

,无论是Criteria,HQL也不能在from子句中使用子查询产生查询,因此您必须使用原生SQL。

相关问题