web-dev-qa-db-ja.com

SQL Serverの関数とストアドプロシージャ

私は長い間関数とストアドプロシージャを学んできましたが、なぜ私が関数やストアドプロシージャを使うべきなのか、そしていつ使うべきかわかりません。彼らは私には同じに見えます、おそらく私はそれについてちょっと初心者だからです。

誰かが私にその理由を教えてもらえますか?

759
Tarik

関数は計算値であり、SQL Serverに対して永続的な環境変更を実行することはできません(つまり、INSERTステートメントまたはUPDATEステートメントは許可されていません)。

関数は、スカラー値を返す場合はSQLステートメント内でインラインで使用することができ、結果セットを返す場合は結合することができます。

答えを要約したコメントから注目に値するポイント。 @Sean K Andersonに感謝します:

関数は、値を返さなければならず、パラメータとして受け取るデータ(引数)を変更することはできないという点で、コンピュータ科学的定義に従います。関数は何も変更することはできず、少なくとも1つのパラメータを持ち、値を返さなければなりません。ストアドプロシージャはパラメータを持つ必要はなく、データベースオブジェクトを変更することも、値を返す必要もありません。

650
MyItchyChin

SPとUDFの違いは以下のとおりです。

+---------------------------------+----------------------------------------+
| Stored Procedure (SP)           | Function (UDF - User Defined           |
|                                 | Function)                              |
+---------------------------------+----------------------------------------+
| SP can return zero , single or  | Function must return a single value    |
| multiple values.                | (which may be a scalar or a table).    |
+---------------------------------+----------------------------------------+
| We can use transaction in SP.   | We can't use transaction in UDF.       |
+---------------------------------+----------------------------------------+
| SP can have input/output        | Only input parameter.                  |
| parameter.                      |                                        |
+---------------------------------+----------------------------------------+
| We can call function from SP.   | We can't call SP from function.        |
+---------------------------------+----------------------------------------+
| We can't use SP in SELECT/      | We can use UDF in SELECT/ WHERE/       |
| WHERE/ HAVING statement.        | HAVING statement.                      |
+---------------------------------+----------------------------------------+
| We can use exception handling   | We can't use Try-Catch block in UDF.   |
| using Try-Catch block in SP.    |                                        |
+---------------------------------+----------------------------------------+
562
Bhaumik Patel

関数とストアドプロシージャは別々の目的を果たします。最もよく似ているわけではありませんが、関数は文字通り他のどのプログラミング言語でも使用できる関数と見なすことができますが、ストアドプロシージャは個々のプログラムやバッチスクリプトのようなものです。

関数は通常出力を持ち、オプションで入力を持ちます。その出力は、別の関数(DATEDIFF、LENなどのSQL Server組み込み)への入力として、またはSQL Queryへの述語(SELECT a, b, dbo.MyFunction(c) FROM tableSELECT a, b, c FROM table WHERE a = dbo.MyFunc(c)など)として使用できます。

ストアドプロシージャは、トランザクション内でSQLクエリをバインドし、外部とのインタフェースをとるために使用されます。 ADO.NETなどのフレームワークは関数を直接呼び出すことはできませんが、ストアドプロシージャを直接呼び出すことはできます。

ただし、関数には隠された危険性があります。それらは誤用され、かなり厄介なパフォーマンスの問題を引き起こす可能性があります。このクエリを考慮してください。

SELECT * FROM dbo.MyTable WHERE col1 = dbo.MyFunction(col2)

MyFunctionは次のように宣言されています。

CREATE FUNCTION MyFunction (@someValue INTEGER) RETURNS INTEGER
AS
BEGIN
   DECLARE @retval INTEGER

   SELECT localValue 
      FROM dbo.localToNationalMapTable
      WHERE nationalValue = @someValue

   RETURN @retval
END

ここで起こることは、関数MyFunctionがテーブルMyTable内のすべての行に対して呼び出されることです。 MyTableに1000行ある場合、それはデータベースに対する別の1000回のアドホッククエリです。同様に、関数がcolumn specで指定されているときに呼び出されると、SELECTによって返される各行に対して関数が呼び出されます。

だからあなたは注意深く関数を書く必要があります。関数内のテーブルからSELECTを実行する場合は、親ストアドプロシージャ内のJOINまたは他のSQL構造体(CASE ... WHEN ... ELSEなど)を使用したほうが適切に実行できるかどうかを確認する必要があります。終わり)。

184
Chris J

他のSQLステートメントで使用するために値を計算して返したい場合は、ユーザー定義関数を作成してください。代わりにストアドプロシージャを作成するのであれば、代わりに複雑なSQLステートメントのセットをグループ化します。結局、これらはまったく異なる2つのユースケースです。

56
Alex Martelli

ストアドプロシージャとユーザー定義関数の違い

  • ストアドプロシージャは、Selectステートメントでは使用できません。
  • ストアドプロシージャは遅延名前解決をサポートします。
  • ストアドプロシージャは通常、ビジネスロジックを実行するために使用されます。
  • ストアドプロシージャは任意のデータ型を返すことができます。
  • ストアドプロシージャは、ユーザー定義関数よりも多くの入力パラメータを受け入れることができます。ストアドプロシージャは、最大21,000の入力パラメータを持つことができます。
  • ストアドプロシージャは動的SQLを実行できます。
  • ストアドプロシージャはエラー処理をサポートします。
  • 非決定的関数はストアドプロシージャで使用できます。

  • ユーザー定義関数は、Selectステートメントで使用できます。
  • ユーザー定義関数は据え置き名前解決をサポートしません。
  • ユーザー定義関数は一般に計算に使用されます。
  • ユーザ定義関数は値を返すべきです。
  • ユーザー定義関数は画像を返すことができません。
  • ユーザー定義関数は、ストアード・プロシージャーよりも少ない数の入力パラメーターを受け入れます。 UDFは最大1,023の入力パラメータを持つことができます。
  • 一時テーブルは、ユーザー定義関数では使用できません。
  • ユーザー定義関数は動的SQLを実行できません。
  • ユーザー定義関数はエラー処理をサポートしません。 RAISEERROR OR @@ERRORは、UDFでは許可されていません。
  • 非決定的関数はUDFでは使用できません。たとえば、GETDATE()はUDFでは使用できません。
55
              STORE PROCEDURE                 FUNCTION (USER DEFINED FUNCTION)    
 * Procedure can return 0, single or   | * Function can return only single value   
   multiple values.                    |
                                       |
 * Procedure can have input, output    | * Function  can have only input 
   parameters.                         |   parameters.         
                                       |
 * Procedure cannot be called from     | * Functions can be called from 
   function.                           |   procedure.
                                       |
 * Procedure allows select as well as  | * Function allows only select statement 
   DML statement in it.                |   in it.
                                       |
 * Exception can be handled by         | * Try-catch block cannot be used in a 
   try-catch block in a procedure.     |   function.
                                       |
 * We can go for transaction management| * We can't go for transaction 
   in procedure.                       |   management in function.
                                       |
 * Procedure cannot be utilized in a   | * Function can be embedded in a select 
   select statement                    |   statement.
                                       |
 * Procedure can affect the state      | * Function can not affect the state 
   of database means it can perform    |   of database means it can not    
   CRUD operation on database.         |   perform CRUD operation on 
                                       |   database. 
                                       |
 * Procedure can use temporary tables. | * Function can not use 
                                       |   temporary tables. 
                                       |
 * Procedure can alter the server      | * Function can not alter the  
   environment parameters.             |   environment parameters.
                                       |   
 * Procedure can use when we want      | * Function can use when we want
   instead is to group a possibly-     |   to compute and return a value
   complex set of SQL statements.      |   for use in other SQL 
                                           statements.
23
Aakash Singh

基本的な違い

関数は値を返さなければなりませんが、ストアドプロシージャではオプションです(プロシージャはゼロまたはn個の値を返すことができます)。

手続きは入力/出力パラメータを持つことができるのに対し、関数はそれに対する入力パラメータのみを持つことができます。

関数は必須の入力パラメータを1つ取りますが、ストアード・プロシージャーはoからn個の入力パラメーターを取ります。

関数はProcedureから呼び出すことができますが、ProcedureはFunctionから呼び出すことはできません。

事前差異

手続きはその中にDML(INSERT/UPDATE/DELETE)文と同様にSELECTを許しますが、関数はその中にSELECT文だけを許します。

手続きはSELECT文の中では利用できませんが、関数はSELECT文の中に埋め込むことができます。

ストアドプロシージャは、WHERE/HAVING/SELECTセクション内のどこにあってもSQLステートメント内で使用することはできませんが、関数は使用できます。

テーブルを返す関数は別の行セットとして扱うことができます。これは他のテーブルとのJOINで使用できます。

インライン関数は、パラメータを取るビューとしても使用でき、JOINや他のRowset操作で使用できます。

Procedureのtry-catchブロックで例外を処理できますが、Functionのtry-catchブロックは使用できません。

手続きでトランザクション管理に進むことができますが、機能に入ることはできません。

ソース

22
Ankit

ユーザー定義関数は、SQL Serverプログラマーが利用できる重要なツールです。あなたはそのようにSQL文の中でそれをインラインで使うことができます

SELECT a, lookupValue(b), c FROM customers 

lookupValueはUDFになります。この種の機能は、ストアドプロシージャを使用している場合は不可能です。同時に、UDFの内部では特定のことができません。ここで覚えておくべき基本的なことは、UDFのことです。

  • 恒久的な変更はできません
  • データを変更することはできません

ストアドプロシージャはそれらのことができます。

私にとって、UDFのインライン使用はUDFの最も重要な使用法です。

19
OpenSource

ストアドプロシージャ はスクリプトとして使用されます 。彼らはあなたのために一連のコマンドを実行し、あなたはそれらが特定の時間に実行されるようにスケジュールすることができます。

関数 をメソッドとして使用します。 あなたはそれを何か渡すと結果を返します。小さくて速いはず - それはその場で行います。

13
Tigerjz32

ストアドプロシージャ:

  • SQL Serverのミニチュアプログラムのようです。
  • Selectステートメントのように単純なものでも、データベース内の複数のテーブルからデータを追加、削除、更新、および/または読み取る長いスクリプトのように複雑なものでもかまいません。
  • (ループとカーソルを実装することができます。どちらを使用しても、小さい結果を処理したり、データに対して行ごとの操作を行うことができます。)
  • EXECまたはEXECUTEステートメントを使用して呼び出す必要があります。
  • テーブル変数を返しますが、OUTパラメータは使用できません。
  • トランザクションをサポートします。

関数:

  • データベースへのレコードの更新、削除、または追加には使用できません。
  • 単一の値またはテーブル値を単純に返します。
  • レコードを選択するためにのみ使用できます。ただし、次のように標準SQLから非常に簡単に呼び出すことができます。

    SELECT dbo.functionname('Parameter1')
    

    または

    SELECT Name, dbo.Functionname('Parameter1') FROM sysObjects
    
  • 単純で再利用可能な選択操作のために、関数はコードを単純化することができます。関数内でJOIN句を使用することには十分注意してください。関数にJOIN句があり、複数の結果を返す別のselect文からそれを呼び出すと、その関数呼び出しは、結果セットに返される each 行に対して、それらのテーブルをまとめてJOINします。そのため、ロジックを単純化するのに役立ちますが、正しく使用されていないとパフォーマンスのボトルネックになる可能性もあります。

  • OUTパラメータを使用して値を返します。
  • トランザクションをサポートしません。
8
JaiSankarN

カーソルなどのSQL Server関数は、最後の武器として使用することを目的としています。これらはパフォーマンスの問題を抱えているので、テーブル値関数の使用はできるだけ避けるべきです。パフォーマンスについて話すのは、ミドルクラスのハードウェア上のサーバーでホストされている1,000,000を超えるレコードを持つテーブルについての話です。それ以外の場合は、機能によるパフォーマンスの低下について心配する必要はありません。

  1. 結果セットを外部コード(ADO.Netなど)に返すために関数を使用しないでください
  2. できるだけビュー/ストアドプロシージャの組み合わせを使用してください。 DTA(Database Tuning Adviser)が(インデックス付きビューや統計のように)あなたに与えるであろう提案を使用して、将来の成長パフォーマンスの問題から回復することができます。

詳細については、以下を参照してください。 http://databases.aspfaq.com/database/should-i-use-a-view-a-stored-procedure-or-a-user-defined-function.html

6
Achilles

次の点が役立つ可能性があるものをいつ使用するかを決定するには、

  1. ストアドプロシージャは、関数がそれを実行できる場所でテーブル変数を返すことはできません。

  2. ストアドプロシージャを使用して、サーバー環境パラメータを変更できます。ただし、関数を使用している場合はできません。

乾杯

6
Arnkrishn

単一の値を返す関数から始めます。いいことに、よく使うコードを関数に入れて、結果セットの列として返すことができます。

それから、あなたは都市のパラメータ化されたリストのために関数を使うかもしれません。 dbo.GetCitiesIn( "NY")結合として使用できるテーブルを返します。

それはコードを体系化する方法です。何が再利用可能でいつそれが時間の浪費であるかを知ることは、試行錯誤と経験を通してしか得られないものです。

また、関数はSQL Serverでは優れたアイデアです。それらはより速く、そしてかなり強力になり得る。インライン選択と直接選択使いすぎないように注意してください。

3
Andrew
  • ストアドプロシージャではありませんが、Functionが値を返すことは必須です。
  • 選択ステートメントはUDFでのみ受け入れられ、DMLステートメントは必要ありません。
  • ストアドプロシージャは、DML文だけでなく任意の文を受け入れます。
  • UDFは入力のみを許可し、出力は許可しません。
  • ストアドプロシージャでは入力と出力の両方が可能です。
  • キャッチブロックはUDFでは使用できませんが、ストアドプロシージャでは使用できます。
  • トランザクションはUDFの関数では許可されていませんが、ストアドプロシージャでは許可されています。
  • UDFではテーブル変数のみを使用でき、一時テーブルは使用できません。
  • ストアドプロシージャでは、テーブル変数と一時テーブルの両方を使用できます。
  • ストアドプロシージャは関数の呼び出しを許可しますが、UDFはストアドプロシージャを関数から呼び出すことを許可しません。
  • UDFはjoin句で使用されますが、ストアドプロシージャはjoin句では使用できません。
  • ストアドプロシージャは常にゼロに戻ることを可能にします。それとは反対に、UDFには、決められたポイントに戻る必要がある値があります。
2
kombsh

これがストアドプロシージャよりも関数を好む実際的な理由です。別のストアドプロシージャの結果を必要とするストアドプロシージャがある場合は、insert-exec文を使用する必要があります。つまり、一時テーブルを作成し、execステートメントを使用してストアドプロシージャの結果を一時テーブルに挿入する必要があります。めちゃくちゃです。これに関する1つの問題は insert-execsを入れ子にすることができないということです

他のストアドプロシージャを呼び出すストアドプロシージャを使用している場合は、これに遭遇する可能性があります。入れ子になったストアドプロシージャが単純にデータセットを返す場合は、テーブル値関数に置き換えることができ、このエラーは発生しなくなります。

これは、ビジネスロジックをデータベースから除外するもう1つの理由です

2
user2023861
  • 手続きでは不可能なところでは、関数はselect文で使用できます。

  • ストアドプロシージャは入力パラメータと出力パラメータの両方を取りますが、関数は入力パラメータのみを取ります。

  • 手続きができるところでは、関数はtext、ntext、image&timestamps型の値を返すことができません。

  • 関数はcreate tableでユーザ定義データ型として使用できますが、プロシージャは使用できません。

***例:table <tablename>(name varchar(10),salary getsal(name))を作成する

ここでgetsalはテーブルが作成されたときに給与タイプに割り当てられたストレージが割り当てられていない、そしてgetal関数も実行されない、ユーザ定義関数です。しかし、このテーブルからいくつかの値を取得しているとき戻り値Typeが結果セットとして返されます。

1
Nick Kahn

これは非常に古い質問であることを私は認識していますが、私は答えのどれにも言及されている1つの重要な側面を見ません:問い合わせ計画へのインライン化。

機能はすることができます...

  1. スカラー:

    CREATE FUNCTION ... RETURNS scalar_type AS BEGIN ... END

  2. 複数ステートメントの表値:

    CREATE FUNCTION ... RETURNS @r TABLE(...) AS BEGIN ... END

  3. インラインテーブル値:

    CREATE FUNCTION ... RETURNS TABLE AS RETURN SELECT ...

3番目の種類(インラインテーブル値)は、クエリオプティマイザによって本質的に(パラメータ化された)ビューとして扱われます。つまり、クエリから関数を参照することは、(実際にはコピー貼り付けせずに)以下の利点があります。

  • クエリプランナは、他のサブクエリと同じようにインライン関数の実行を最適化することができます(たとえば、未使用の列の削除、述語のプッシュダウン、さまざまなJOIN戦略の選択など)。
  • いくつかのインライン関数を組み合わせることで、次の関数に渡す前に最初の関数の結果を具体化する必要はありません。

上記のことは、特に複数レベルの機能を組み合わせる場合に、潜在的に著しいパフォーマンスの節約につながる可能性があります。


注:SQL Server 2019では、何らかの形式の スカラー関数のインライン展開 が導入される予定です。

1

ユーザー定義関数

  1. 関数は値を返す必要があります。
  2. Selectステートメントのみを許可し、DMLステートメントの使用を許可しません。
  3. 入力パラメーターのみを許可し、出力パラメーターをサポートしません。
  4. Try-catchブロックを使用することはできません。
  5. 関数内ではトランザクションは許可されていません。
  6. テーブル変数のみを使用できますが、一時テーブルの使用は許可されません。
  7. ストアドプロシージャを関数から呼び出すことはできません。
  8. 関数はselectステートメントから呼び出すことができます。
  9. UDFは、結果セットとして結合句で使用できます。

ストアドプロシージャ

  1. ストアドプロシージャは値を返す場合と返さない場合があります。
  2. Selectステートメントと、挿入、更新、削除などのDMLステートメントを持つことができます
  3. 入力パラメーターと出力パラメーターの両方を持つことができます。
  4. 例外処理には、try catchブロックを使用できます。
  5. ストアドプロシージャ内でトランザクションを使用できます。
  6. テーブル変数と一時テーブルの両方を使用できます。
  7. ストアドプロシージャは関数を呼び出すことができます。
  8. Select/Where/Havingなどのステートメントからプロシージャを呼び出すことはできません。ストアドプロシージャの呼び出し/実行には、Execute/Execステートメントを使用できます。
  9. プロシージャはJoin句では使用できません
0
Mahesh Waghmare