Приходилось ли работать с индексами и оптимизировать запросы?
Что проверяют
Понимаете ли вы, что медленный запрос в Java-приложении чаще рождается в маппинге, чем в базе. Интервьюер смотрит, связываете ли вы три слоя: JPQL или Criteria, реальный SQL от Hibernate и план этого SQL. Уточнение обычно такое: «как вы ловили N+1» и «какие индексы завели».
Как отвечать
Начните с того, чем смотрели:
- на стороне приложения:
hibernate.generate_statisticsи счётчик запросов на транзакцию,p6spyилиdatasource-proxyвместо бесполезногоshow-sql, метрики HikariCP в Actuator, JFR или async-profiler, когда время уходит не в базу; - на стороне базы:
pg_stat_statements,EXPLAIN (ANALYZE, BUFFERS),auto_explainдля того, что не воспроизводится руками.
Дальше две группы находок. Слой ORM: @ManyToOne и @OneToOne по умолчанию EAGER, это главный поставщик лишних запросов; лечится переводом в LAZY плюс JOIN FETCH, @EntityGraph или @BatchSize. Пагинация вместе с JOIN FETCH коллекции заставляет Hibernate вытянуть всё в память и резать страницу там, поэтому идентификаторы страницы берут отдельным запросом. Пакетная вставка требует hibernate.jdbc.batch_size и order_inserts, а GenerationType.IDENTITY батчинг отключает.
Слой базы: составной индекс под конкретный запрос с правильным порядком колонок (равенство, затем диапазон и сортировка), частичный под горячий фильтр. Заводите их миграцией Flyway или Liquibase, а не аннотацией @Index с ddl-auto.
Хорошо закончить проверкой: тест, считающий число запросов на сценарий, ловит возврат N+1 надёжнее ручного замера. Опыта мало: скажите честно, назвав, что делали на уровне самих запросов.
Где спотыкаются
Винят базу, когда виноват маппинг. Двести запросов по одному на элемент списка не лечатся индексом, и ответ «добавили индекс» выдаёт, что человек не смотрел на реальный SQL.
Не знают про spring.jpa.open-in-view, включённый в Spring Boot по умолчанию. Он дотягивает ленивые связи при сериализации ответа, прячет N+1 от тестов и держит соединение всю обработку.
Пробуют вытащить две коллекции одним JOIN FETCH, получают MultipleBagFetchException и наугад меняют List на Set, не понимая, что дело в декартовом произведении строк.