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)