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)