Что такое хранимые процедуры в SQL?
Что проверяют
Знаете ли вы механизм и умеете ли обосновать, стоит ли переносить логику в базу. Для команды на Go это решение с последствиями: код на сервере базы не попадает в репозиторий сам, не проверяется компилятором и требует отдельной дисциплины миграций.
Как отвечать
Хранимая процедура это именованный блок кода, который хранится в базе и вызывается по имени. В PostgreSQL процедуру вызывают через call, и главное отличие от функции в том, что она может управлять транзакцией внутри себя, тогда как функция всегда выполняется внутри транзакции вызывающего.
Из Go процедуру без выходных параметров зовут как команду, а не как запрос:
_, err := db.ExecContext(ctx, "call archive_orders($1)", before)Чтобы получить значение, процедуре объявляют параметр inout, и тогда вызов возвращает строку, которую читают обычным способом.
Плюсы называют честно: меньше обращений по сети для многошаговой операции, атомарность рядом с данными, права выдаются на вызов, а не на таблицы. Минусы тоже: логика уезжает из репозитория, отладка и обзор кода хуже, тесты требуют живой базы, а ошибки приходят в Go строками. Разумная граница проходит по объёму данных: то, что должно выполняться близко к данным одним куском, уместно в базе, а бизнес-правила обычно нет.
Где спотыкаются
Повторяют миф о предварительной компиляции. Ускорение даёт не сам факт хранения, а сокращение обращений и кеш планов в рамках сессии, причём сохранённый общий план иногда оказывается хуже подобранного под конкретные параметры.
Пытаются обернуть вызов в транзакцию приложения. Процедура, делающая внутри себя фиксацию, в чужой транзакции завершится ошибкой, и решается это при проектировании, а не повторным вызовом.
Считают процедуру защитой от внедрения SQL. Защищают параметры запроса, а не место хранения кода: динамический запрос, собранный внутри процедуры склейкой строк, уязвим ровно так же.