Java, кодирующий лучшие практики для многократного использования части запроса для подсчета

Clojure становится довольно близко ...

5
задан Community 23 May 2017 в 12:09
поделиться

4 ответа

Хороший вопрос. Вот что я делал в прошлом (многие вещи вы уже упоминали):

  1. Проверяйте, присутствует ли предложение SELECT .
    1. В противном случае добавьте select count (*)
    2. В противном случае проверьте, есть ли в нем DISTINCT или агрегатные функции. Если вы используете ANTLR для анализа вашего запроса, это можно обойти, но это довольно сложно. Скорее всего, вам лучше просто обернуть все это с помощью select count (*) from () .
  2. Remove fetch all properties
  3. Remove fetch from join если вы разбираете HQL как строку. Если вы действительно анализируете запрос с помощью ANTLR, вы можете полностью удалить left join ; довольно сложно проверять все возможные ссылки.
  4. Удалить , упорядочить по
  5. В зависимости от того, что вы сделали в 1.2, вам нужно будет удалить / настроить группу с помощью / имеющий .

Вышесказанное, естественно, относится к HQL. Для запросов Criteria вы довольно ограничены в том, что можете делать, потому что они не поддаются легким манипуляциям. Если вы используете какой-то слой-оболочку поверх Criteria, вы получите эквивалент (ограниченного) подмножества результатов синтаксического анализа ANTLR, и в этом случае вы сможете применить большую часть вышеперечисленного.

удерживайте смещение текущей страницы и общее количество, я обычно сначала запускаю фактический запрос с заданным пределом / смещением и запускаю запрос count (*) только в том случае, если количество возвращаемых результатов больше или равно предел И смещение равно нулю (во всех остальных случаях я либо запускал count (*) раньше, либо все равно получил обратно все результаты). Конечно, это оптимистичный подход в отношении одновременных модификаций.

Обновление (о ручной сборке HQL)

Мне такой подход не особенно нравится. При отображении как именованный запрос HQL имеет преимущество проверки ошибок во время сборки (ну, технически во время выполнения, потому что SessionFactory должен быть построен, хотя обычно это делается во время тестирования интеграции). Когда генерируется во время выполнения, он не работает во время выполнения :-) Оптимизация производительности тоже не совсем простая.

Те же рассуждения применимы, конечно, к критериям, но немного сложнее облажаться из-за четко определенного API, чем конкатенация строк. Параллельное построение двух HQL-запросов (один с разбивкой по страницам и один с «глобальным счетчиком») также приводит к дублированию кода (и потенциально большему количеству ошибок) или вынуждает вас писать какой-то слой-оболочку поверх, чтобы сделать это за вас. Оба пути далеки от идеала. И если вам нужно сделать это из клиентского кода (например, через API), проблема усугубится.

Я действительно довольно много размышлял над этой проблемой. API поиска из Hibernate-Generic-DAO кажется разумным компромиссом; более подробная информация содержится в моем ответе на связанный выше вопрос.

1
ответ дан 14 December 2019 в 13:41
поделиться

Пробовали ли вы прояснить свои намерения для Hibernate, установив проекцию по вашим (SQL?) Критериям? Я в основном использовал критерии, поэтому я не уверен, насколько это применимо к вашему случаю, но я использовал

getSession().createCriteria(persistentClass).
setProjection(Projections.rowCount()).uniqueResult()

и позволял Hibernate самостоятельно определять кэширование / повторное использование / умные вещи .. Не совсем уверен сколько умных вещей он на самом деле делает .. Кто-нибудь хочет это прокомментировать?

3
ответ дан 14 December 2019 в 13:41
поделиться

Ну, я не уверен, что это лучшая практика, но моя-практика :)

Если у меня есть запрос, например:

select A.f1,A.f2,A.f3 from A, B where A.f2=B.f2 order by A.f1, B.f3

И я просто хочу знать, сколько результатов будет получено, я выполняю:

select count(*) from ( select A.f1, ... order by A.f1, B.f3 )

А затем получаю результат как целое число, без отображения результатов в POJO.

Разбирать ваш запрос на удаление некоторых частей, например, «упорядочить по» очень сложно. Хорошая СУБД оптимизирует ваш запрос.

Хороший вопрос.

2
ответ дан 14 December 2019 в 13:41
поделиться

В ситуации HQL от руки я бы использовал что-то вроде этого, но это нельзя использовать повторно, так как это довольно специфично для заданных сущностей

Integer count = (Integer) session.createQuery("select count(*) from ....").uniqueResult();

Сделайте это один раз и соответствующим образом скорректируйте начальный номер, пока не пройдете страницу .

Хотя для критериев я использую пример вроде этого

final Criteria criteria = session.createCriteria(clazz);  
            List<Criterion> restrictions = factory.assemble(command.getFilter());
            for (Criterion restriction : restrictions)
                criteria.add(restriction);
            criteria.add(Restrictions.conjunction());
            if(this.projections != null)
                criteria.setProjection(factory.loadProjections(this.projections));
            criteria.addOrder(command.getDir().equals("ASC")?Order.asc(command.getSort()):Order.desc(command.getSort()));
            ScrollableResults scrollable = criteria.scroll(ScrollMode.SCROLL_INSENSITIVE);
            if(scrollable.last()){//returns true if there is a resultset
                genericDTO.setTotalCount(scrollable.getRowNumber() + 1);
                criteria.setFirstResult(command.getStart())
                        .setMaxResults(command.getLimit());
                genericDTO.setLineItems(Collections.unmodifiableList(criteria.list()));
            }
            scrollable.close();
            return genericDTO;

Но он подсчитывает каждый раз, вызывая ScrollableResults: last () .

0
ответ дан 14 December 2019 в 13:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: