Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Що таке збережені процедури й функції в MySQL і коли їх краще уникати?

Збережена процедура - іменований блок SQL з параметрами, що виконується на сервері через CALL. Збережена функція повертає одне значення і використовується у виразах.

DELIMITER //

CREATE PROCEDURE close_month(IN p_month DATE)
BEGIN
    START TRANSACTION;
    INSERT INTO monthly_totals (month, total)
    SELECT p_month, SUM(amount) FROM payments
    WHERE created_at >= p_month AND created_at < p_month + INTERVAL 1 MONTH;
    UPDATE payments SET closed = 1
    WHERE created_at >= p_month AND created_at < p_month + INTERVAL 1 MONTH;
    COMMIT;
END //

CREATE FUNCTION vat(amount DECIMAL(12,2)) RETURNS DECIMAL(12,2)
DETERMINISTIC NO SQL
RETURN amount * 0.2 //

DELIMITER ;

CALL close_month('2026-09-01');
SELECT id, vat(total) FROM orders;

DELIMITER - команда клієнта mysql, а не сервера: тіло процедури містить ;, тож клієнту потрібен інший роздільник. Через PDO (і DB::unprepared() у Laravel) він не потрібен - запит надсилається цілком.

Характеристики функції - DETERMINISTIC, NO SQL, READS SQL DATA. Якщо ввімкнено бінарний журнал, MySQL відмовиться створити функцію без цих позначок (або без log_bin_trust_function_creators): недетермінована функція могла б дати різні результати на джерелі й репліці. Позначка - обіцянка: неправдиве DETERMINISTIC MySQL не перевіряє.

Коли процедури доречні:

  • обробка великих обсягів даних без передачі їх у застосунок;
  • спільна логіка для кількох застосунків на різних мовах, що працюють з однією базою;
  • адміністративні операції, які запускає DBA.

Чому в застосунках на Laravel їх зазвичай уникають:

  • тестування й налагодження складніші: немає Pest, покриття, нормального налагоджувача;
  • деплой і версіонування: код живе в міграціях, рев'ю й відкат незручні, легко розійтися між середовищами;
  • масштабування: база - найважче для масштабування місце, а логіка в ній додає навантаження;
  • обмеження: функції й тригери не можуть змінювати таблицю, яку вже читає оператор, що їх викликав; рекурсивні функції заборонені;
  • знання в команді: критична логіка на мові, якою команда пише рідко.

Виклик з Laravel: DB::select('CALL report_for(?)', [$month]) для процедури з результатом, DB::statement('CALL close_month(?)', [...]) - без нього. Помилка з SIGNAL SQLSTATE '45000' приходить як QueryException.

Докладніше в документації: MySQL: CREATE PROCEDURE і CREATE FUNCTION

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання