web-dev-qa-db-ja.com

MySQLストアドプロシージャと関数、いつ使用しますか?

私はMySQLのストアドプロシージャと関数を見ています。本当の違いは何ですか?

これらは似ているように見えますが、機能にはさらに制限があります。

私は間違っている可能性が高いですが、ストアドプロシージャはすべてを実行でき、ストアドファンクションはもっと実行できるようです。なぜ/いつプロシージャと関数を使用するのですか?

149
Anonym

ストアドプロシージャと通常のSQLを混在させることはできませんが、ストアドファンクションを使用することはできます。

例えばSELECT get_foo(myColumn) FROM mytableは、get_foo()がプロシージャの場合は無効ですが、get_foo()が関数の場合は実行できます。代償として、関数には手続きよりも多くの制限があります。

92
nos

プロシージャと関数の最も一般的な違いは、それらが異なる方法で、異なる目的で呼び出されることです:

  1. プロシージャは値を返しません。代わりに、CALLステートメントで呼び出され、テーブルの変更や取得したレコードの処理などの操作を実行します。
  2. 関数は式内で呼び出され、式で使用される単一の値を呼び出し元に直接返します。
  3. CALLステートメントで関数を呼び出すことはできません。また、式でプロシージャを呼び出すこともできません。

ルーチン作成の構文は、プロシージャと関数で多少異なります:

  1. プロシージャパラメータは、入力専用、出力専用、またはその両方として定義できます。これは、プロシージャが出力パラメータを使用して呼び出し元に値を渡すことができることを意味します。これらの値は、CALLステートメントに続くステートメントでアクセスできます。関数には入力パラメーターのみがあります。その結果、プロシージャと関数の両方にパラメータを設定できますが、プロシージャのパラメータ宣言は関数の宣言とは異なります。
  2. 関数は値を返すため、関数定義には戻り値のデータ型を示すRETURNS句が必要です。また、呼び出し元に値を返すには、関数本体内に少なくとも1つのRETURNステートメントが必要です。 RETURNSおよびRETURNは、プロシージャ定義には表示されません。

    • ストアドプロシージャを呼び出すには、CALL statementを使用します。ストアド関数を呼び出すには、式でそれを参照します。この関数は、式の評価中に値を返します。

    • プロシージャはCALLステートメントを使用して呼び出され、出力変数を使用してのみ値を返すことができます。関数は、他の関数と同じように(つまり、関数の名前を呼び出すことにより)ステートメント内から呼び出すことができ、スカラー値を返すことができます。

    • パラメーターをIN、OUT、またはINOUTとして指定することは、PROCEDUREに対してのみ有効です。 FUNCTIONの場合、パラメーターは常にINパラメーターと見なされます。

    パラメーター名の前にキーワードが指定されていない場合、デフォルトでINパラメーターになります。 ストアド関数のパラメーターの前にIN、OUT、またはINOUTはありません。すべての関数パラメーターはINパラメーターとして扱われます。

ストアドプロシージャまたは関数を定義するには、それぞれCREATE PROCEDUREまたはCREATE FUNCTIONを使用します:

CREATE PROCEDURE proc_name ([parameters])
 [characteristics]
 routine_body


CREATE FUNCTION func_name ([parameters])
 RETURNS data_type       // diffrent
 [characteristics]
 routine_body

ストアドプロシージャ(関数ではない)のMySQL拡張機能は、プロシージャが結果セット、または複数の結果セットを生成できることであり、呼び出し元はSELECTステートメントの結果と同じ方法で処理します。ただし、そのような結果セットの内容を式で直接使用することはできません。

ストアドルーチン(ストアドプロシージャとストアド関数の両方を参照)は、テーブルまたはviews。データベースを削除すると、データベース内のストアドルーチンもすべて削除されます。

ストアドプロシージャと関数は同じ名前空間を共有しません。データベース内に同じ名前のプロシージャと関数を持つことができます。

ストアドプロシージャでは動的SQLを使用できますが、関数またはトリガーでは使用できません。

SQL準備済みステートメント(PREPARE、EXECUTE、DEALLOCATE PREPARE)は、ストアドプロシージャで使用できますが、ストアドファンクションまたはトリガーでは使用できません。したがって、ストアド関数とトリガーは動的SQLを使用できません(ステートメントを文字列として構築してから実行します)。 (MySQLストアドルーチンの動的SQL)

FUNCTIONとSTORED PROCEDUREのさらに興味深い違い:

  1. このポイントは ブログ投稿からコピーされた)ストアドプロシージャはプリコンパイルされた実行計画であり、関数はそうではありません。実行時に解析およびコンパイルされた関数。ストアドプロシージャ、データベースに擬似コードとして、つまりコンパイルされた形式で保存されます。

  2. この点についてはわかりません。
    ストアドプロシージャにはセキュリティがあり、ネットワークトラフィックを軽減します。また、ストアドプロシージャを呼び出すことができます。一度にアプリケーションの。 参照

  3. 関数は通常、計算に使用されますが、プロシージャは通常、ビジネスロジックの実行に使用されます。

  4. 関数はデータベースの状態に影響を与えることはできません(明示的または暗黙的なコミットまたはロールバックを行うステートメントは機能上許可されません)ストアドプロシージャはコミットなどを使用してデータベースの状態に影響を与える可能性があります.
    refrence: J.1。ストアドルーチンとトリガーの制限

  5. 関数は FLUSH ステートメントを使用できませんが、ストアドプロシージャは使用できます。

  6. ストアドプロシージャは再帰できますが、ストアドファンクションは再帰できません。注:再帰ストアドプロシージャはデフォルトでは無効になっていますが、max_sp_recursion_depthサーバーシステム変数をゼロ以外の値に設定することにより、サーバー上で有効にできます。詳細については、 セクション5.2.3、「システム変数」 を参照してください。

  7. ストアド関数またはトリガー内では、関数またはトリガーを呼び出したステートメントによって既に(読み取りまたは書き込み用に)使用されているテーブルを変更することはできません。良い例: MYSQLで削除時に同じテーブルを更新する方法?

:ストアドプロシージャではなく、ストアドファンクションとトリガーに通常いくつかの制限が適用されますが、これらの制限は内部から呼び出された場合、ストアドプロシージャに適用されますストアド関数またはトリガー。たとえば、ストアドプロシージャでFLUSHを使用できますが、そのようなストアドプロシージャはストアドファンクションまたはトリガから呼び出すことはできません。

245
Grijesh Chauhan

大きな違いの1つは、SQLクエリに function を含めることができることですが、 ストアドプロシージャCALL ステートメントでのみ呼び出すことができます。

UDFの例:

CREATE FUNCTION hello (s CHAR(20))
   RETURNS CHAR(50) DETERMINISTIC
   RETURN CONCAT('Hello, ',s,'!');
Query OK, 0 rows affected (0.00 sec)

CREATE TABLE names (id int, name varchar(20));
INSERT INTO names VALUES (1, 'Bob');
INSERT INTO names VALUES (2, 'John');
INSERT INTO names VALUES (3, 'Paul');

SELECT hello(name) FROM names;
+--------------+
| hello(name)  |
+--------------+
| Hello, Bob!  |
| Hello, John! |
| Hello, Paul! |
+--------------+
3 rows in set (0.00 sec)

Sprocの例:

delimiter //

CREATE PROCEDURE simpleproc (IN s CHAR(100))
BEGIN
   SELECT CONCAT('Hello, ', s, '!');
END//
Query OK, 0 rows affected (0.00 sec)

delimiter ;

CALL simpleproc('World');
+---------------------------+
| CONCAT('Hello, ', s, '!') |
+---------------------------+
| Hello, World!             |
+---------------------------+
1 row in set (0.00 sec)
49
Daniel Vassallo

ストアド関数はクエリ内で使用できます。その後、すべての行に適用するか、WHERE句内で適用できます。

CALLクエリを使用してプロシージャが実行されます。

8
Evert

ストアドプロシージャは再帰的に呼び出すことができますが、ストアドファンクションはできません

0
palash140