我们在项目中经常使用Criteria进行动态查询生成。我真的很喜欢查询的表达方式。问题是我们发现这个特定的查询无法使用基于clientId的索引,所以我们需要更改它。这是工作的非索引查询:
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;
}
此查询只能使用startTime索引,并且无法使用任何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();
使用索引比使用原始查询更糟糕,并且不会在FROM中进行子选择。
所以我的问题是,我可以在标准中执行此操作,还是我坚持使用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)
这是hibernate标准子查询的解释:
+----+--------------------+-------+-----------------+---------------------------------------+---------+---------+------+-------+-------------+
| 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)
答案 0 :(得分:3)
据我所知,Criteria
和HQL都不能在from
子句中生成带子查询的查询,因此您必须使用本机SQL。