Hibernate, производительность JDBC и Java на средних и больших результатах - PullRequest
19 голосов
/ 20 декабря 2011

Issue

Мы пытаемся оптимизировать наше приложение для обработки данных.Он хранит акции и котировки в базе данных MySQL.И мы не удовлетворены результатами выборки.

Контекст

- database
    - table stock : around 500 lines
    - table quote : 3 000 000 to 10 000 000 lines
    - one-to-many association : one stock owns n quotes
    - fetching around 1000 quotes per request
    - there is an index on (stockId,date) in the quote table
    - no cache, because in production, querys are always different
- Hibernate 3
- mysql 5.5
- Java 6
- JDBC mysql Connector 5.1.13
- c3p0 pooling

Тесты и результаты

Протокол

  • Время выполнения на сервере MySQLполучены с запуском сгенерированных запросов sql в bin командной строки mysql.
  • Сервер находится в тестовом контексте: нет других чтений БД, нет записей БД
  • Мы получаем 857 кавычек для акций AAPL

Случай 1: Hibernate с ассоциацией

Это заполняет наш фондовый объект 857 объектами кавычек (все правильно отображается в hibernate.xml)

session.enableFilter("after").setParameter("after", 1322910573000L);
Stock stock = (Stock) session.createCriteria(Stock.class).
add(Restrictions.eq("stockId", stockId)).
setFetchMode("quotes", FetchMode.JOIN).uniqueResult();

SQLсгенерировано:

SELECT this_.stockId AS stockId1_1_,
       this_.symbol AS symbol1_1_,
       this_.name AS name1_1_,
       quotes2_.stockId AS stockId1_3_,
       quotes2_.quoteId AS quoteId3_,
       quotes2_.quoteId AS quoteId0_0_,
       quotes2_.value AS value0_0_,
       quotes2_.stockId AS stockId0_0_,
       quotes2_.volume AS volume0_0_,
       quotes2_.quality AS quality0_0_,
       quotes2_.date AS date0_0_,
       quotes2_.createdDate AS createdD7_0_0_,
       quotes2_.fetcher AS fetcher0_0_
FROM stock this_
LEFT OUTER JOIN quote quotes2_ ON this_.stockId=quotes2_.stockId
AND quotes2_.date > 1322910573000
WHERE this_.stockId='AAPL'
ORDER BY quotes2_.date ASC

Результаты:

  • Время выполнения на сервере MySQL: ~ 10 мс
  • Время выполнения в Java: ~ 400 мс

Случай 2: Hibernate без ассоциации без HQL

В целях повышения производительности мы использовали этот код, который выбирает только объекты кавычек, и добавляем вручнуюих на склад (поэтому мы не получаем повторную информациюо запасе для каждой линии).Мы использовали createSQLQuery, чтобы минимизировать эффекты псевдонимов и беспорядка HQL.

String filter = " AND q.date>1322910573000";
filter += " ORDER BY q.date DESC";
Stock stock = new Stock(stockId);
stock.addQuotes((ArrayList<Quote>) session.createSQLQuery("select * from quote q where stockId='" + stockId + "' " + filter).addEntity(Quote.class).list());

Сгенерированный SQL:

SELECT *
FROM quote q
WHERE stockId='AAPL'
  AND q.date>1322910573000
ORDER BY q.date ASC

Результаты:

  • Время выполнения на сервере MySQL: ~ 10 мс
  • Время выполнения в Java: ~ 370 мс

Случай 3: JDBC без спящего режима

String filter = " AND q.date>1322910573000";
filter += " ORDER BY q.date DESC";
Stock stock = new Stock(stockId);
Connection conn = SimpleJDBC.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from quote q where stockId='" + stockId + "' " + filter);
while(rs.next())
{
    stock.addQuote(new Quote(rs.getInt("volume"), rs.getLong("date"), rs.getFloat("value"), rs.getByte("fetcher")));
}
stmt.close();
conn.close();

Результаты:

  • Время выполнения на сервере MySQL: ~ 10 мс
  • Время выполнения в Java: ~ 100 мс

Наше понимание

  • Драйвер JDBC является общим для всех случаев
  • Существуют фундаментальные затраты времени на вождение JDBC
  • С аналогичным sqlВ запросах Hibernate тратит больше времени, чем чистый код JDBC, на преобразование наборов результатов в объекты
  • Hibernate createCriteria, createSQLQuery или createQuery схожи во времени и стоимости
  • В производстве, где у нас много одновременной записи,Чистое решение JDBC казалось медленнее спящего (возможно, потому что наши JDBCЧисло операций не было объединено)
  • Mysql, сервер, кажется, ведет себя очень хорошо, и стоимость времени очень приемлема

Наши вопросы

  • ЕстьЕсть ли способ оптимизировать производительность драйвера JDBC?
  • И принесет ли Hibernate эту оптимизацию?
  • Есть ли способ оптимизировать производительность Hibernate при преобразовании наборов результатов?
  • мы сталкиваемся с чем-то не настраиваемым из-за фундаментальных объектов Java и управления памятью?
  • Мы упускаем точку, мы глупы, и все это напрасно?
  • Мы французы?Да.

Ваша помощь очень приветствуется.

1 Ответ

7 голосов
/ 20 декабря 2011

Можете ли вы сделать тест на дым с помощью простого запроса:

SELECT current_timestamp()

или

SELECT 1 + 1

Это скажет вам, каковы фактические издержки драйвера JDBC. Также неясно, выполняются ли оба теста с одной и той же машины.

Есть ли способ оптимизировать производительность драйвера JDBC?

Выполнять один и тот же запрос несколько тысяч раз на Java. JVM требуется некоторое время для прогрева (загрузка классов, JIT). Также я предполагаю, что SimpleJDBC.getConnection() использует пул соединений C3P0 - стоимость установления соединения довольно высока, поэтому первые несколько операций могут быть медленными.

Также предпочитайте именованные запросы специальным запросам или критериям запроса.

И будет ли Hibernate полезен для этой оптимизации?

Hibernate - очень сложный фреймворк. Как видите, он потребляет 75% общего времени выполнения по сравнению с необработанным JDBC. Если вам нужен сырой ORM (без отложенной загрузки, грязной проверки, расширенного кэширования), рассмотрите mybatis . Или, может быть, даже JdbcTemplate с RowMapper абстракция.

Есть ли способ оптимизировать производительность Hibernate при преобразовании наборов результатов?

Не совсем. Ознакомьтесь с Глава 19. Повышение производительности в документации Hibernate. Существует много отражений, происходящих там + генерация классов. Еще раз, Hibernate не может быть лучшим решением, когда вы хотите выжать каждую миллисекунду из вашей базы данных.

Однако - это хороший выбор, если вы хотите повысить общее удобство работы пользователя из-за широкой поддержки кэширования. Проверьте производительность документ снова. В основном это говорит о кешировании. Существует кэш первого уровня, кэш второго уровня, кеш запросов ... Это то место, где Hibernate может на самом деле превзойти простой JDBC - он может кешировать многое способами, которые вы даже не могли себе представить. С другой стороны - плохая конфигурация кэша приведет к еще более медленной установке.

Проверить: Кеширование с Hibernate + Spring - некоторые вопросы!

Мы сталкиваемся с чем-то не настраиваемым из-за фундаментальных объектов Java и управления памятью?

JVM (особенно в конфигурации server ) работает довольно быстро. Создание объектов в куче происходит так же быстро, как в стеке, например С, сборка мусора была значительно оптимизирована. Я не думаю, что Java-версия с простым JDBC будет намного медленнее по сравнению с более родным соединением. Вот почему я предложил несколько улучшений в вашем тесте.

Неужели мы упускаем точку, мы глупы, и все это напрасно?

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...