Подтвердить что ты не робот

Простой запрос на спящий режим, возвращающийся очень медленно

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

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

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

Добавленная информация: После добавления записи в спящий режим я вижу

[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 в первой реализации, как я могу узнать?

4b9b3361

Ответ 1

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

Ответ 2

Основываясь на новой информации, я чувствовал, что должен дать другой ответ. Разница выглядит так: у вас есть ассоциация "один ко многим", заданная для свойства "Список" или "Набор" в вашем bean.

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

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

Ответ 3

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

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

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

Ответ 4

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

Запрос на спящий режим:

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

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

  • Измените мои HQL на собственные запросы и добавьте OPTION RECOMPILE ДЛЯ НЕКОТОРЫХ ПАРАМ

  • Используйте прямые значения запроса вместо подготовленных операторов, чтобы не было перевода значений параметров, и запросы не будут изменены как хранимые процедуры с помощью драйвера

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

Я не хотел использовать OPTION 1 и 2, поскольку это устраняет всю цель использования ORM Framework, и я в конечном итоге использую OPTION 3 на данный момент

Итак, я изменил URL JDBC для отправки опции prepareStatement = false

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

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

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

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

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

Ответ 5

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

В 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">

Ответ 6

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

    Long count = getStoreCount(customerId);

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

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

Ответ 7

Мне потребовалось 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 секунды для выполнения любых запросов.