Ответ 1
Добавление конструктора со всеми атрибутами класса сделало трюк, теперь время выполнения составляет 70 мс для запроса на спящий режим. Раньше класс имел только конструктор по умолчанию без аргументов и конструктор с аргументом id объекта.
У меня есть следующий запрос на спящий режим:
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 в первой реализации, как я могу узнать?
Добавление конструктора со всеми атрибутами класса сделало трюк, теперь время выполнения составляет 70 мс для запроса на спящий режим. Раньше класс имел только конструктор по умолчанию без аргументов и конструктор с аргументом id объекта.
Основываясь на новой информации, я чувствовал, что должен дать другой ответ. Разница выглядит так: у вас есть ассоциация "один ко многим", заданная для свойства "Список" или "Набор" в вашем bean.
Вероятно, вы указали, что lazy=false
отключит ленивую загрузку. При выключенной ленивой загрузке она будет извлекать каждую связанную запись для каждого объекта MyHibernateClass
, и поэтому она так долго выполняется.
Попробуйте установить lazy=true
, и это будет выполняться намного быстрее, а затем только извлекать связанные объекты, когда явным образом запрашивает их у объекта.
Если вы используете Log4j в своем приложении, вы можете задать множество различных параметров ведения журнала, относящихся к Hibernate, чтобы получить лучшее представление о том, что происходит за кулисами в Hibernate.
Я предполагаю, что это типичное начальное время загрузки, которое возникает при первом вызове запроса HQL в приложении. Последующие запросы HQL должны быть заметно и значительно быстрее после этого первого.
Я знаю, что этот поток устарел, но для обновления я столкнулся с той же проблемой, но с 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. Насколько мне известно, приложение работает быстро и быстро. Я также представил кэши второго уровня, чтобы кэшировать его в течение некоторого времени.
Надеюсь, что это поможет кому-то, если у вас есть хорошее предложение, пожалуйста, дайте мне знать.
Я знаю, что это старый вопрос, но вот что исправлено для меня...
В 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">
У меня был инцидент, когда мое приложение всегда использовало каждую строку в результирующем наборе запроса. Я нашел 40-кратное увеличение скорости, установив свой размер выборки, используя метод setFetchSize ниже. (Улучшение производительности включает добавление запроса count.)
Long count = getStoreCount(customerId);
Query query = session.getNamedQuery("hqlGetStoresByCustomerId")
.setString("i_customerid",customerId)
.setFetchSize(count.intValue());
Будьте осторожны, делая это; мой набор данных имел около 100 строк, и он был охвачен жизнью веб-запроса. Если у вас есть большие наборы данных, вы будете кушать Java Heap на время существования этих данных, прежде чем возвращать его в кучу Java.
Мне потребовалось 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 секунды для выполнения любых запросов.