ResultSet.next очень медленный, только если запрос содержит ограничение FIRST_ROWS или ROWNUM - PullRequest
4 голосов
/ 14 января 2012

Я выполняю собственный запрос, используя

entityManager.createNativeQuery(sqlQuery);
query.setMaxResults(maxResults);

List<Object[]> resultList = query.getResultList();

Чтобы ускорить запрос, я подумал включить подсказку или ограничение FIRST_ROWS(n), используя WHERE ROWNUM > n.

Используя инструментарий, яобратите внимание, что на самом деле OraclePreparedStatement.executeQuery быстрее, но на EJBQueryImpl.getResultList затрачивается гораздо больше времени, что в целом приводит к очень низкой производительности.Рассматривая более подробно, я вижу, что каждый 10-й вызов ResultSet.next() занимает примерно столько же времени, сколько и сам executeQuery ().Это странное поведение прекращается, когда я пропускаю подсказку запроса или условие ROWNUM, тогда каждый 10-й вызов resultset.next несколько ниже, чем другие, но только 2 мс вместо 3 секунд.

Ответы [ 3 ]

2 голосов
/ 16 января 2012

Похоже, вы сделали JDBC executeQuery быстрее, но JDBC ResultSet в следующий раз медленнее. Вы сделали выполнение запроса быстрее, но получение данных медленнее. Кажется, это проблема JDBC, а не EclipseLink, вы получите тот же результат через необработанный JDBC, если вы действительно извлечете данные.

10 - это размер выборки по умолчанию, так что вы можете попробовать увеличить его.

См, http://www.eclipse.org/eclipselink/api/2.3/org/eclipse/persistence/config/QueryHints.html#JDBC_FETCH_SIZE

2 голосов
/ 14 января 2012

Получаете ли вы разные планы запросов, когда включаете подсказку?Я предполагаю, что вы делаете, основываясь на своем описании проблемы.

Когда вы выполняете запрос в Oracle, база данных обычно не материализует весь набор результатов в любой момент времени (очевидно, возможно, придетсяесли вы укажете предложение ORDER BY, которое требует, чтобы все данные были материализованы до сортировки).Oracle фактически не начинает материализовывать данные, пока клиент не начнет получать данные.Он выполняет достаточно запроса, чтобы сгенерировать сколько угодно строк, которые клиент запросил для выборки (в вашем случае это звучит как 10), возвращает эти результаты клиенту и ждет, пока клиент запросит дополнительные данные, прежде чем продолжить обработку запроса.query.

Похоже, что при включении подсказки FIRST_ROWS план запроса изменяется таким образом, что его выполнение обходится дороже.Очевидно, что это не цель FIRST_ROWS подсказки.Цель состоит в том, чтобы сказать оптимизатору сгенерировать план, который делает выборку первых N строк более эффективной, даже если это делает выборку всех строк из запроса менее эффективной.Это приводит к тому, что оптимизатор предпочитает такие операции, как сканирование индекса, а не сканирование таблицы, где сканирование таблицы может быть более эффективным в целом.Похоже, в вашем случае оценки оптимизатора неверны, и в итоге выбирается план, который в целом менее эффективен.Это часто означает, что некоторые статистические данные по некоторым объектам, на которые ссылается ваш запрос, являются неполными или неверными.

0 голосов
/ 16 января 2012

Попробуйте добавить ограничение максимального числа строк в SQL напрямую, вместо использования setMaxResults, т.е. добавьте, где rownum

...