次の方法で共有


パラメーターと実行プランの再利用

ADO、OLE DB、ODBC の各アプリケーションのパラメーター マーカーなどのパラメーターを使用すると、実行プランの再利用回数を増やすことができます。

セキュリティに関する注意セキュリティに関する注意

パラメーターまたはパラメーター マーカーを使用してエンド ユーザーが入力した値を保持する方法は、後からデータ アクセス API メソッド、EXECUTE ステートメント、または sp_executesql ストアド プロシージャのいずれかを使用して実行される文字列に値を連結する方法よりも安全です。

次の 2 つの SELECT ステートメントでは、WHERE 句で比較する値のみが異なっています。

SELECT * 
FROM AdventureWorks2008R2.Production.Product 
WHERE ProductSubcategoryID = 1;

SELECT * 
FROM AdventureWorks2008R2.Production.Product 
WHERE ProductSubcategoryID = 4;

これらのクエリの実行プランでは、ProductSubcategoryID 列に対して比較用に格納された値のみが異なります。最終的な目標は、ステートメントが生成するプランは基本的に同じであると SQL Server に常に認識させてプランを再利用することにありますが、SQL ステートメントが複雑になると SQL Server がこのことを検出できない場合があります。

パラメーターを使用して SQL ステートメントと定数を切り離すと、同一のプランをリレーショナル エンジンが認識できるようになります。パラメーターは、次の方法で使用できます。

  • Transact-SQL では、sp_executesql を次のように使用します。

    DECLARE @MyIntParm INT
    SET @MyIntParm = 1
    EXEC sp_executesql
      N'SELECT * 
      FROM AdventureWorks2008R2.Production.Product 
      WHERE ProductSubcategoryID = @Parm',
      N'@Parm INT',
      @MyIntParm
    

    この方法は、SQL ステートメントを動的に生成する Transact-SQL スクリプト、ストアド プロシージャ、またはトリガーで使用することをお勧めします。

  • ADO、OLE DB、および ODBC ではパラメーター マーカーを使用します。パラメーター マーカーは疑問符 (?) です。SQL ステートメント内の定数の代わりに置かれ、プログラム変数にバインドされます。たとえば、ODBC アプリケーションでは次のような操作を実行できます。

    • SQLBindParameter を使用して、整数変数を SQL ステートメントの最初のパラメーター マーカーにバインドします。

    • 変数に整数値を代入します。

    • 次のように、パラメーター マーカー (?) を指定してステートメントを実行します。

      SQLExecDirect(hstmt, 
        "SELECT * 
        FROM AdventureWorks2008R2.Production.Product 
        WHERE ProductSubcategoryID = ?",
        SQL_NTS);
      

      アプリケーション内でパラメーター マーカーが使用されると、SQL Server に装備されている SQL Server Native Client OLE DB プロバイダーと SQL Server Native Client ODBC ドライバーが sp_executesql を使用して SQL Server にステートメントを送信します。

  • ストアド プロシージャをデザインする場合は、意図的にパラメーターを使用できます。

アプリケーションのデザインにパラメーターを明示的に組み込まない場合は、簡易パラメーター化 の既定の動作を使用して、SQL Server クエリ オプティマイザーで自動的に特定のクエリをパラメーター化することもできます。また、ALTER DATABASE ステートメントの PARAMETERIZATION オプションを FORCED に設定することで、クエリ オプティマイザーにデータベース内のすべてのクエリをパラメーター化するように強制できます。詳細については、「強制パラメータ化」を参照してください。

強制パラメーター化が有効になっている場合でも、簡易パラメーター化が行われる可能性はあります。たとえば、強制パラメーター化のルールに従えば、次のクエリはパラメーター化できません。

SELECT * FROM Person.Address
WHERE AddressID = 1 + 2;

ただし、簡易パラメーター化のルールに従ってパラメーター化することはできます。強制パラメーター化の試行に失敗した場合でも、簡易パラメーター化が続けて試行されます。