Рекомендации для повышения производительности Java Persistence

Введение

Высокопроизводительный доступ к слою данных требует много знаний об устройстве базы данных, JDBC, JPA, Hibernate, и этот пост содержит самые важные техники, которые Вы можете использовать для оптимизации вашего enterprise приложения.

1. Логирование SQL выражений

Если Вы используете фреймворк, который генерирует выражения от вашего лица, Вы должны всегда валидировать каждое выражение на эффективность и производительность.

2. Управление соединениями

Соединения к базе данных дорого обходятся, поэтому Вы должны всегда использовать механизм пула соединений.

Из-за того что количество соединений задается возможностями кластера базы данных, необходимо освобождать ресурсы соединений как можно быстрее.

При тюнинге производительности Вы всегда должны измерять и устанавливать правильный размер пула. Инструменты наподобие FlexyPool могут помочь найти правильный размер даже если Вы задеплоили Ваше приложение на продакшн сервер.

3. Батчинг JDBC

JDBC батчинг позволяет нам отправлять многочисленные SQL выражения в одном сеансе соединения с базой данных. Выгода в производительности существенна как со стороны драйвера, так и со стороны базы данных. PreparedStatements являются очень подходящими кандидатами для батчинга, и так же некоторые СУБД (например Oracle) поддерживают батчинг только для PreparedStatements.

С тех пор как в JDBC ввели  API для батчинга (например, PreparedStataement.addBatch и PreparedStatement.executeBatch), в случае если Вы генерируете выражения вручную, то Вы должны знать с самого начала, можете ли Вы использовать пакетную обработку или нет. С Hibernate, Вы можете переключить на батчинг всего навсего одной настройкой в конфигурации.

Hibernate 5.2 предлагает  Session-level batching, что является еще более гибким решением в это плане.

4. Кэширование выражений

Кэширование выражений является одним из наименее известных оптимизаций производительности, которой Вы можете воспользоваться. В зависимости от нижележащего JDBC драйвера, Вы можете кэшировать PreparedStatements как с клиентской стороны (драйвер), так и со стороны базы данных (синтаксическое дерево или даже план выполнения).

5. Идентификаторы Hibernate

Использование Hibernate IDENTITY генератора является не самым хорошим выбором, потому что он делает невозможным батчинг JDBC.

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

SEQUENCE — правильный выбор и даже SQL Server поддерживает с версии 2012. Для SEQUENCE идентификаторов Hibernate уже давно предлагает оптимайзеры наподобие  pooled or pooled-lo, которые могут уменьшить количество обращений к базе данных, требуемых для загрузки значения идентификатора новой сущности.

6. Правильно выбираем типы данных для столбцов

Вы должны всегда правильно использовать типы столбцов на стороне СУБД. Чем более компактен тип столбца, тем больше записей может быть размещено в БД и индексы будут лучше размещаться в памяти. Для этих целей Вы должны использовать преимущества специфичных для СУБД типов (например inet для адресов вида IPv4 в PostgreSQL), особенно с того времени как в Hibernate ввели очень гибкий кастомный тип Type

7. Реляционные отношения

Hibernate предоставляет множество типов маппинга реляционных отношений, но все из них равны с точки зрения эффективности.

Всегда избегайте однонаправленные ассоциации и @ManyToMany. Для коллекций предпочтительней использовать двунаправленную ассоциацию @OneToMany.

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

8. Наследование

Когда дело доходит до наследования, различия между объектно-ориентированными языками и реляционными базами данных становится еще более очевидным. JPA предлагает SINGLE_TABLE, JOIN, и TABLE_PER_CLASS для наследования при маппинге и каждая из этих стратегий имеет плюсы и минусы.

SINGLE_TABLE выполняет лучшие с точки зрения SQL выражения, но мы теряем в целостности данных из-за невозможности использовать NOT NULL ограничения.

JOIN  решает проблемы с целостностью данных предлагая более сложные выражения. Пока Вы не используете полиморфные запросы или @OneToMany ассоциации к базовым типам, эта стратегия работает хорошо. Настоящая мощь исходит из полиморфных @ManyToOne ассоциаций опирающихся на шаблон Strategy на стороне слоя доступа к данным.

TABLE_PER_CLASS необходимо избегать с тех пор как эта стратегия генерирует неэффективные SQL выражения.

9. Размер Persistence Context

При использовании JPA и Hibernate Вы всегда должны держать в уме размер Persistence контекста. По этой причине Вы должны не раздувать его сотнями управляемых сущностей. Уменьшая количество управляемых сущностей, мы достигаем значительное улучшение управления памятью и дефолтовый механизм dirty checking будет работать более эффективно!

10. Выгружайте только то что действительно необходимо

Выгрузка больших объемов данных вероятно причина номер один для проблем с производительностью слоя доступа к данным. Проблема в том, что запросы для сущностей используются исключительно, даже для операций чтения.

DTO проекции больше подходят для выгрузки кастомных views, в то время как сущности должны выгружаться только когда поток действий бизнес-логики требует изменить их.

EAGER выгрузка самая худшая и Вы должны избегать анти-паттерны такие как Open-Session in View.

11.Кэширование

Реляционные СУБД используют множество in-memory буферов для экономии ресурсов дисков. Кэширование СУБД очень часто упускают из виду. Мы можем значительно уменьшить время ответа настройкой движка СУБД так что рабочие наборы данных находятся в памяти и не выгружаются с диска постоянно.

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

Кэш второго уровня очень полезен для уменьшения времени ответа для транзакции на чтение-запись, особенно при архитектуре репликаций Master-Slave. В зависимости от требований, Hibernate предлагает следующие стратегии: READ_ONLYNONSTRICT_READ_WRITE, READ_WRITE, и TRANSACTIONAL.

12. Контроль concurrency

Выбор уровня изолированности транзакций имеет первостепенный приоритет, когда дело доходит до быстродействия и целостности данных. Для потоков с многочисленными вызовами, чтобы избежать потери обновленных данных, Вы должны использовать оптимистическую блокировку или EXTENDED Persistence Context.

13. Вертикальное и горизонтальное масштабирование

Реляционные СУБД хорошо подвергаются масштабированию. Если  Facebook, Twitter, Pinterest или StackOverflow могут масштабировать свои СУБД, то есть хороший шанс для того чтобы Вы смогли масштабировать enterprise приложение соответствуя бизнес требованиям.

Репликация и сегментирование БД — это очень хорошие варианты для увеличения пропускной способности и Вы должны полностью воспользоваться преимуществами этих архитектурных шаблонов для масштабирования Вашего приложения.

 

(Visited 892 times, 1 visits today)

One thought to “Рекомендации для повышения производительности Java Persistence”

  1. Пара вопросов:

    1. «Для коллекций предпочтительней использовать двунаправленную ассоциацию @OneToMany»
    — Почему для коллекций лучше использовать двунаправленные связи?
    — Двунаправленная связь, это разве не @ManyToOne + @OneToMany?

    2. «Реляционные СУБД хорошо подвергаются масштабированию.»
    хорошо относительно чего? Относительно noSql — вроде как наоборот, очень все сложно….. Мне же наоборот казалось, что это недостаток RDBMS.

    Спасибо за познавательный сайт!

Добавить комментарий

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.