Простой запрос гибернации, возвращающийся очень медленно - PullRequest
24 голосов
/ 07 июля 2011

У меня есть следующий запрос гибернации:

Query query = session.createQuery("from MyHibernateClass");
List<MyHibernateClass> result = query.list();// executes in 7000ms

При регистрации SQL, выполняемого в MySQL, я вижу

select 
  myhibernat0_.myFirstColumn as myfirstcolumn92_, 
  myhibernat0_.mySecondColumn as mysecondcolumn92_, 
  myhibernat0_.mythirdcolumn as mythirdcolumn92_, 
  myhibernat0_.myFourthColumn as myfourthcolumn92_ 
from MyHibernateClass myhibernat0_ 
where (1=1);

При измерении кода Java в jvm на небольшом наборе данныхиз 3500 строк в таблице базы данных MyHibernateClass это занимает около 7000 мс.

Если я, с другой стороны, использую прямой jdbc следующим образом:

Statement statement = session.connection().createStatement();
ResultSet rs = statement.executeQuery("select * from MyHibernateClass");// 7ms
List<MyHibernateClass> result = convert(rs);// executes in 20ms

Я вижу, что тот же sql входит в базу данных, но теперьвремя, потраченное на java-код в jvm, составляет 7 мс.

MyHibernateClass - это простой класс Java-бина с геттерами и сеттерами, я не использую специальных преобразователей результата, как видно из примера.Мне нужен только экземпляр класса, доступный только для чтения, и его не нужно присоединять к сеансу гибернации.

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

Добавлена ​​информация : после добавления журнала гибернации я вижу

[2011-07-07 14:26:26,643]DEBUG [main] [logid: ] - 
  org.hibernate.jdbc.AbstractBatcher.logOpenResults(AbstractBatcher.java:426) - 
  about to open ResultSet (open ResultSets: 0, globally: 0)

, за которым следуют 3500 следующих операторов журнала

[2011-07-07 14:26:26,649]DEBUG [main] [logid: ] - 
  org.hibernate.loader.Loader.getRow(Loader.java:1197) - 
  result row: EntityKey[com.mycom.MyHibernateClass#1]

, а затем 3500 операторов журналакак

[2011-07-07 14:27:06,789]DEBUG [main] [logid: ] - 
  org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:130) - 
  resolving associations for [com.mycom.MyHibernateClass#1]
[2011-07-07 14:27:06,792]DEBUG [main] [logid: ] - 
  org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:226) - 
  done materializing entity [com.mycom.MyHibernateClass#1]

Что это значит?

Что делает Hibernate в первой реализации, как я могу узнать?

Ответы [ 7 ]

28 голосов
/ 08 июля 2011

Добавление конструктора со всеми атрибутами класса сделало свое дело, теперь время выполнения составляет 70 мс для запроса гибернации.Ранее у класса был только конструктор по умолчанию без аргументов и конструктор с аргументом идентификатора сущности.

6 голосов
/ 07 июля 2011

Исходя из новой информации, я решил дать другой ответ.Разница выглядит так, что в вашем bean-компоненте определена ассоциация «один ко многим» для свойства List или Set.

Возможно, вы указали lazy=false, что отключит отложенную загрузку.При отключенной отложенной загрузке он будет извлекать каждую связанную запись для каждой MyHibernateClass сущности, и поэтому выполнение занимает так много времени.

Попробуйте установить lazy=true, и это будет выполняться намного быстрее, а затем только извлекатьсвязанные сущности при явном запросе их у сущности.

4 голосов
/ 01 января 2015

Я знаю, что этот поток старый, но для обновления я столкнулся с той же проблемой, но с SQL Server, и оказалось, что SQL, печатаемый с помощью Hibernate и SQL Sent с использованием драйвера, отличается.При использовании драйвера MSSQL по умолчанию запросы отправляются как хранимые процедуры, так как вызовы RPC вызваны тем, что драйвер пытается оптимизировать план запросов для стандартов MSSQL, поэтому он отправляет запросы примерно так:

Запрос Hibernate:

select c.col1,c.col2 from customer c where c.name like @param1 and c.country like @param2

Фактический драйвер отправил запрос:

@param1=somevalue, @param2=somevalue 
declar sp ....

  select c.col1,c.col2 from customer c where c.name like @param1 and c.country like @param2
go

Примечание. Этот запрос я получил через инструмент SQL Profiler Tool, непосредственно прослушивающий DB

Оказывается, что оптимизация sp_exec на MSSQL приводит к созданию хороших планов запросов, которые кэшируются, но это приведет к «анализу параметров», чтобы узнать больше об этой проблеме, читайте здесь ...

Чтобы преодолеть это, у меня были следующие опции:

  1. Измените мой HQL на собственные запросы и добавьте OPTION RECOMPILE FOR SOME PARAM

  2. Use Directзначения запроса вместо подготовленных операторов, поэтому не будет никакого перевода значений параметров, и запросы не будут изменены драйвером как хранимые процедуры

  3. Изменить tНастройки драйвера не отправляют хранимые процедуры (это все еще плохо, потому что теперь планы запросов на MSSQL-сервере будут специфичны для этого запроса, это то же самое, что Option: 2, но вне кода)

Я не хотел использовать ВАРИАНТЫ 1 и 2, так как это исключает всю цель использования ORM Frameworks, и я заканчиваю тем, что на данный момент использую ВАРИАНТ 3

Поэтому я изменил URL-адрес JDBC для отправки опции prepareStatement =false

После установки этой проблемы у меня возникла еще одна проблема, связанная с отправкой запроса, например

 Select * from customer c where c.name like **N**'somename' and c.country=**N**'somevalue'

Здесь перед значениями стоит префикс, указывающий, что преобразовать схему кодирования, поэтому я отключаюURL JDBC для sendUnicode = false

Это все, что я сделал в настройках драйвера JTDS. Насколько я понимаю, теперь приложение работает и работает быстро.Я также ввел кеш второго уровня для его кеширования в течение некоторого времени.

Надеюсь, это кому-нибудь поможет, если у вас есть хорошие предложения, пожалуйста, дайте мне знать.

4 голосов
/ 07 июля 2011

Если вы используете Log4j в своем приложении, вы можете установить различные параметры ведения журнала, специфичные для Hibernate, чтобы получить лучшее представление о том, что происходит за кулисами в Hibernate.

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/session-configuration.html#configuration-logging

Я предполагаю, что это типичное время начальной загрузки, которое происходит при первом вызове HQL-запроса в приложении. Последующие HQL-запросы должны быть заметно и значительно быстрее после первого.

1 голос
/ 22 июля 2015

У меня был инцидент, когда мое приложение всегда использовало каждую строку в наборе результатов запроса.Я нашел 40-кратное увеличение скорости, установив размер выборки с помощью метода setFetchSize, приведенного ниже.(Улучшение производительности включает добавление запроса подсчета.)

    Long count = getStoreCount(customerId);

    Query query = session.getNamedQuery("hqlGetStoresByCustomerId")
            .setString("i_customerid",customerId)
            .setFetchSize(count.intValue());

Будьте осторожны при этом;у моего набора данных было около 100 строк, и он был ограничен сроком службы веб-запроса.Если у вас есть большие наборы данных, вы будете есть кучу Java на время существования этих данных, прежде чем вернуть их в кучу Java.

1 голос
/ 19 июня 2015

Я знаю, что это старый вопрос, но вот что исправило его для меня ...

В вашем hibernate.cfg.xml убедитесь, что у вас есть правильный! DOCTYPE ... он должен выглядеть следующим образом:

<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
0 голосов
/ 28 сентября 2015

Мне потребовалось 10 секунд, чтобы выполнить простой запрос выбора всех, прежде чем я обнаружил, что тег DOCTYPE неправильно записан в hibernate.cfg.xml и *mapping object*.hbm.class

Убедитесь, что hibernate.cfg.xml начинается с

<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

И отображение xml.class с

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

Теперь мне потребовалось 1-2 секунды, чтобы выполнить любые запросы.

...