Приходилось ли работать с хранимыми процедурами?
Что проверяют
Есть ли у вас опыт за пределами ORM и понимаете ли вы цену переноса логики в базу. Ответ «да, вызывал» не устраивает никого, ждут разговора про плюсы, минусы и технику вызова из кода.
Как отвечать
Сначала за что их берут: сокращение числа обращений к базе там, где иначе нужен цикл запросов, обработка больших объёмов рядом с данными вместо перекачки их в приложение, выдача прав на выполнение процедуры вместо прав на таблицы, единая точка для логики, которую дёргают несколько разных клиентов.
Затем про вызов из Java: CallableStatement с синтаксисом вида {call proc(?, ?)} и registerOutParameter для выходных значений, в JPA это StoredProcedureQuery или описание аннотацией, в Spring удобен SimpleJdbcCall. Полезно помнить, что в PostgreSQL функция всегда выполняется внутри транзакции вызывающего, процедура через CALL может управлять транзакцией сама, а возвращённый наружу курсор читается в той же транзакции.
Минусы называйте сами, иначе их назовут за вас: логика уезжает из репозитория и из ревью, отладка и юнит-тесты хуже, язык процедур привязывает к конкретной СУБД, а процессорное время базы масштабируется тяжелее и дороже, чем время сервиса приложений.
Где спотыкаются
Обещают ускорение как свойство самой процедуры. Выигрыш даёт сокращение обращений и объёма передаваемых данных, а тот же одиночный запрос, обёрнутый в процедуру, быстрее не станет. Проценты, названные без замера и без описания нагрузки, ответу только вредят.
Забывают про жизненный цикл. Процедуру меняют в базе руками, версии в репозитории нет, откат релиза её не откатывает, и через полгода никто не знает, какая версия где стоит. Ожидаемый ответ: те же миграции и то же ревью, что и для кода.
Промахиваются на технике вызова. Не закрывают CallableStatement и держат соединение, теряют выходные параметры, обрабатывают ошибку процедуры как рядовое исключение, хотя разбирать её обычно нужно по коду ошибки СУБД.