web-dev-qa-db-ja.com

ストアドプロシージャEXECとsp_executesqlの違いは?

sp_executesqlを使用して2つのストアドプロシージャを記述しましたが、sp_executesqlを使用していないストアドプロシージャは両方とも同じ結果を適切に実行しています。

EXEC(@SQL)vs EXEC sp_executesql @ SQL、N '@ eStatus varchar(12)'、@ eStatus = @Status

また、EXEC(@SQL)はSQLインジェクションを起こしやすく、sp_executesql @SQL ......はそうではありませんか?

Sp_executesqlを使用しないストアドプロシージャの下

ALTER proc USP_GetEmpByStatus
(
@Status varchar(12)
)
AS
BEGIN
DECLARE @TableName AS sysname = 'Employee'
Declare @Columns as sysname = '*'
DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + @TableName + ' where Status=' + char(39) + @Status + char(39)
print (@SQL)
EXEC (@SQL)
END

EXEC USP_GetEmpByStatus 'Active'

以下のストアドプロシージャとsp_executesql

create proc USP_GetEmpByStatusWithSpExcute
(
@Status varchar(12)
)
AS
BEGIN
DECLARE @TableName AS sysname = 'JProCo.dbo.Employee'
Declare @Columns as sysname = '*'
DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + @TableName + ' where Status=' + char(39) + @Status + char(39)
print @SQL
exec sp_executesql @SQL, N'@eStatus varchar(12)', @eStatus = @Status
END

EXEC USP_GetEmpByStatusWithSpExcute 'Active'
25
Registered User

あなたのsp_executesql SQLはおそらくそうです;

DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + 
            @TableName + ' where Status=@eStatus'

これにより、SQLに埋め込む代わりに、パラメータとして@eStatusを指定してsp_executesqlを呼び出すことができます。これにより、@ eStatusには任意の文字を含めることができ、安全が必要な場合はデータベースによって自動的に適切にエスケープされるという利点があります。

[〜#〜] exec [〜#〜];に必要なSQLとは対照的です。

DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + 
            @TableName + ' where Status=' + char(39) + @Status + char(39)

... @ Statusに埋め込まれたchar(39)は、SQLを無効にし、SQLインジェクションの可能性を作成します。たとえば、@ StatusがO'Reillyに設定されている場合、結果のSQLは次のようになります。

select acol,bcol,ccol FROM myTable WHERE Status='O'Reilly'
19

使用法の他に、いくつかの重要な違いがあります。

  1. sp_executesqlを使用すると、ステートメントをパラメーター化できます。したがって、SQLインジェクションに関してはEXECよりも安全です。

  2. sp_executesqlは、キャッシュされたクエリプランを活用できます。 TSQL文字列は一度だけ構築され、その後、同じクエリがsp_executesqlで呼び出されるたびに、SQL Serverはキャッシュからクエリプランを取得して再利用します

  3. EXECで作成された一時テーブルは、一時テーブルキャッシングメカニズムを使用できません

19
FLICKER

sp_executesql、そのようなクエリを作成する必要はありません。次のように宣言できます。

DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + 
@TableName + ' where Status=@eStatus'

このようにすると、@Status値は、使用できるユーザーからのものです@eStatusエスケープについて心配する必要はありません'。 sp_executesqlを使用すると、連結を使用する代わりに、変数を文字列形式でクエリに含めることができます。したがって、心配する必要はありません。

列変数とテーブル変数は同じままですが、ユーザーから直接送信される可能性は低くなります。

4
JeffB

WithExecT-Sqlステートメント文字列にプレースホルダーを含めることはできません。

sp_executesqlは、プレースホルダーを持ち、runtimeで実際の値を渡すという利点を提供します

2
Mohammadreza