Как смотреть и оптимизировать запросы в Hibernate?
Что проверяют
Умеете ли вы увидеть реальный SQL, который генерирует Hibernate, и найти в нём N+1. Это главное, кэш и тонкие настройки вторичны. Следом обычно просят объяснить, чем JOIN FETCH отличается от @EntityGraph и почему выборка коллекции через JOIN FETCH ломает пагинацию.
Как отвечать
Сначала как смотреть:
- логирование SQL:
spring.jpa.show-sql=trueпишет в stdout без параметров, поэтому лучше логгерorg.hibernate.SQLнаDEBUG, а для значений параметров в Hibernate 6org.hibernate.orm.jdbc.bindнаTRACE; - статистика:
hibernate.generate_statistics=trueпоказывает число запросов и время на сессию. Внезапные 200 запросов на один эндпоинт сразу видны; - прокси над DataSource: datasource-proxy или p6spy логируют итоговый SQL с параметрами и позволяют в тестах проверять число запросов, чтобы N+1 не вернулся;
- сама база:
EXPLAIN ANALYZEдля медленного запроса иpg_stat_statementsв PostgreSQL для самых дорогих запросов на проде.
Потом как лечить:
- N+1:
JOIN FETCHв JPQL или@EntityGraphпод конкретный сценарий, для коллекций ещё@BatchSizeилиhibernate.default_batch_fetch_size, который грузит связи пачками черезIN; - ленивая загрузка: у
@ManyToOneи@OneToOneпо умолчаниюEAGER, их стоит явно делатьLAZY; - проекции: для списков DTO через
select newили интерфейсные проекции Spring Data, без загрузки сущностей в контекст; - запись:
hibernate.jdbc.batch_sizeвместе сhibernate.order_inserts, помня, что генераторIDENTITYотключает пакетную вставку; - чтение:
@Transactional(readOnly = true)снимает затраты на dirty checking.
Где спотыкаются
Делают JOIN FETCH коллекции вместе с Pageable. Hibernate выгружает всё и режет страницу в памяти, оставляя об этом предупреждение в логе, а на большой таблице это падение по памяти.
Фетчат две коллекции типа List одним запросом и получают MultipleBagFetchException или декартово произведение строк.
Лечат N+1 кэшем второго уровня. Он маскирует проблему: на холодном кэше и после инвалидации те же сотни запросов возвращаются, а в придачу появляется вопрос согласованности данных.