次の方法で共有


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

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

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

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

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

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

SELECT * FROM AdventureWorks.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 AdventureWorks.Production.Product WHERE ProductSubcategoryID = @Parm',
      N'@Parm INT',
      @MyIntParm
    

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

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

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

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

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

      SQLExecDirect(hstmt, 
        "SELECT * FROM AdventureWorks.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;

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