Могу ли я использовать критерии Hibernate для генерации подзапроса в предложении from? - PullRequest
1 голос
/ 31 января 2012

Мы часто используем критерии в нашем проекте для динамической генерации запросов. Мне очень нравится, как выражаются запросы. Проблема в том, что мы обнаружили, что этот конкретный запрос не может быть выполнен с использованием индексов, основанных на 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 и не может использовать индексы с любым из идентификаторов клиента. Я обнаружил, что следующая форма запроса эффективно использует наши индексы, и я хочу создать этот запрос с критериями:

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)

1 Ответ

3 голосов
/ 31 января 2012

Насколько я знаю, ни Criteria, ни HQL не могут создавать запросы с подзапросами в предложении from, так что вам придется использовать собственный SQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...