Медленная производительность на Hibernate + Java, но быстро, когда я использую TOAD с тем же собственным запросом Oracle
Я обнаружил проблему с производительностью с гибернацией и встроенными запросами в Oracle. Когда я выполняю сложный SQL-запрос с несколькими параметрами в TOAD, я получаю результат в miliseconds. Однако при выполнении одного и того же запроса с использованием Hibernate это время увеличивается с увеличением (до четырех секунд или даже больше).
Мой SQL-запрос довольно сложный, возвращает уникальное значение (поэтому проблема не связана с временем, необходимым для классов instation) и содержит несколько параметров с форматом: nameParameter. Этот запрос хранится в строке. Например,
String myNamedNativeQuery = "select count(*) from tables "+
"where column1 = :nameParameter1 "+
"and column2 = :nameParameter2";
//actually my sentence is much more complex!!
Когда я выполняю предложение в TOAD, он разрешается за несколько миллисекунд. Но используя это предложение с Hibernate
SQLQuery query = session.createSQLQuery("myNamedNativeQuery");
query.setParameter(nameParameter1, value1);
query.setParameter(nameParameter2, value2);
query.uniqueResult();
необходимы несколько секунд, чтобы получить тот же результат.
Я понял, что заменил параметры непосредственно на собственный запрос, а затем выполнил предложение, используя Hibernate, время резко сократилось. Это было бы так:
String strQuery = session.getNamedQuery("myNamedNativeQuery").getQueryString();
myNamedNativeQuery = myNamedNativeQuery.replace("nameParameter1", value1);
myNamedNativeQuery = myNamedNativeQuery.replace("nameParameter2", value2);
SQLQuery query = session.createSQLQuery("myNamedNativeQuery");
query.uniqueResult();
Кто-нибудь знает, что происходит???
Спасибо заранее.
PS: версия Oracle - это 9i и Hibernate 3.2
Ответы
Ответ 1
Я думаю, что происходит с этим кодом:
SQLQuery query = session.createSQLQuery("myNamedNativeQuery");
query.setParameter(nameParameter1, value1);
query.setParameter(nameParameter2, value2);
query.uniqueResult();
:
в строке 1: план запросов создается на основе некоторых ожидаемых значений для ваших именованных параметров.
в строке 4: запрос выполняется со значением1 и значением2, но эти значения не являются "хорошими значениями" для плана запроса, который был разработан в строке 1, и поэтому база данных выполняет очень неулокальный план для фактических значений и это занимает много времени.
Почему?
Посмотрев исходный код HibernateSessionImpl.createSQLQuery(...)
, я нашел эту строку кода:
SQLQueryImpl query = new SQLQueryImpl(
sql,
this,
factory.getQueryPlanCache().getSQLParameterMetadata( sql )
);
который вызывает getQueryPlanCache()
с некоторым параметромMetaData. Я предполагаю, что эти метаданные недостаточно хороши.
Ответ 2
Мой ответ вам:
Удалите все параметры привязки и используйте StatelessSession вместо сеанса
Использовать SQLQuery вместо запроса с полным SQL, включая значения параметров
StatelessSession session = sessionFactory.openStatelessSession();
У меня была схожая проблема, и пока я не получу лучшее решение, мне удалось заставить ее работать.
См. Hibernate параметризованный SQL-запрос медленных и активных сеансов оракула