ストアドプロシージャ
Stored Procedure
複数のSQL文で構成される複雑な処理手順を、あらかじめデータベース側に保存しておき、1つのコマンドで呼び出せるようにしたプログラムのこと。
🐾 猫で例えると?
頭に鏡餅の飾りを乗せた茶トラ。「飾りを用意する」→「頭に乗せる」→「写真を撮る」という一連の手順を考えます。これを毎回イチから指示するのではなく、「猫かぶり処理」として事前に登録しておくことで、一発で実行できるようにした状態がストアドプロシージャです。
💻 データベース開発における「ストアドプロシージャ」とは?
アプリケーションを開発する際、データベースに対して「データを検索して、計算して、別のテーブルを更新して…」といった複数のSQLを順番に実行したい場面が多々あります。通常はアプリケーション側からSQLを1つずつ発行しますが、これだとネットワーク通信の回数が増え、処理が遅くなる原因となります。
複数のSQLをDB側でまとめて実行すると、アプリとDBの往復を減らせる場合があります。ただし、処理内容や実行計画によって性能は変わり、ストアドプロシージャにするだけで必ず速くなるわけではありません。
⚠️ ストアドプロシージャの仕組みと注意点
実行権限を整理し、DB操作の入口を限定する用途にも使えます。ただし、内部で入力を連結した動的SQLを作ればSQLインジェクションの危険は残ります。パラメータの適切な利用と、必要最小限の権限が重要です。
ブラックボックス化の罠
次はMySQLの例です。usersとpoint_historyが存在し、対象の利用者IDが有効であることを前提とします。DELIMITERはmysqlクライアントの区切り設定で、サーバーへ送るSQL文ではありません。プロシージャはCALLで呼び出し、行の更新を契機に動くトリガーとは区別します。
-- MySQLでのストアドプロシージャの作成例
DELIMITER //
CREATE PROCEDURE UpdateUserPoints(IN userId INT, IN addPoints INT)
BEGIN
-- 1. ユーザーのポイントを更新
UPDATE users SET points = points + addPoints WHERE id = userId;
-- 2. ポイント履歴テーブルにログを追加
INSERT INTO point_history (user_id, added_points, created_at)
VALUES (userId, addPoints, NOW());
END //
DELIMITER ;
-- アプリケーション側からの呼び出し(これ1行で済む)
CALL UpdateUserPoints(101, 500); この例は2つのSQLをまとめていますが、BEGINとENDは処理のまとまりを表し、それだけでトランザクションにはなりません。両方を一体として確定するには、トランザクション対応テーブルを使い、呼び出し側などで開始・確定・エラー時のロールバックを設計します。
🛠️ ストアドプロシージャを賢く使うためのポイント
現場でストアドプロシージャを導入する際は、運用面でのルール決めが不可欠です。
- バージョン管理を徹底する: アプリケーションのソースコードと違い、DB上のプロシージャはGitなどで管理しにくいため、DDL(定義文)のスクリプトファイルをしっかりバージョン管理する必要があります。
- ビジネスロジックを持たせすぎない: DB側に複雑な業務ルール(計算式や条件分岐など)を書きすぎると、保守性が著しく低下します。データの操作に特化させましょう。
- DBの移行(マイグレーション)が困難になる: プロシージャの記述ルールはデータベース製品(Oracle, MySQL, PostgreSQLなど)によって異なるため、将来的なDB移行の大きな障壁(ベンダーロックイン)になります。
猫との決まった手順のように、繰り返すDB操作をまとめるのがストアドプロシージャです。性能、権限、テストのしやすさを確かめながら、アプリ側に置く処理との境界を決めましょう。