2012-01-31 100 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。

相關問題