準備実行
ODBC API では、準備実行とは、Transact-SQL ステートメントを繰り返し実行する際に関連して生じる解析やコンパイルのオーバーヘッドを削減する方法と定義されています。アプリケーションでは SQL ステートメントを保持する文字列を構築してから、そのステートメントを 2 段階に分けて実行します。まず、SQLPrepare を 1 回呼び出すと、データベース エンジンでステートメントが解析され、実行プランにコンパイルされます。次に、この準備された実行プランの各実行に対して SQLExecute を呼び出します。この方法では、各実行にかかる解析とコンパイルのオーバーヘッドが抑制されます。準備実行は、通常、同一のパラメータ化された SQL ステートメントを繰り返し実行するアプリケーションで使用されます。
ほとんどのデータベースでは、直接実行されるステートメントが実行のたびにコンパイルされるのに対し、準備実行されるステートメントは 1 回だけコンパイルされるので、準備実行は主に 4、5 回以上実行されるステートメントの場合は直接実行よりも高速になります。準備実行では、SQL ステートメントが実行されるたびに、ドライバはステートメント全体ではなく、実行プランの識別子とパラメータ値だけをデータ ソースに送信できるので、ネットワーク トラフィックも削減できます。
SQL Server 2000 以降では、SQLExecDirect が実行プランを検出し再利用するアルゴリズムが強化されたので、直接実行と準備実行のパフォーマンスの差異が少なくなります。そのため、直接実行されるステートメントでも、準備実行のパフォーマンス上の利点の一部を利用できるようになります。詳細については、「直接実行」を参照してください。
SQL Server 2000 以降では、準備実行がネイティブにサポートされます。実行プランは SQLPrepare で構築され、その後 SQLExecute が呼び出されると実行されます。SQL Server 2000 以降では、SQLPrepare で一時ストアド プロシージャを構築する必要がないので、tempdb のシステム テーブルに余分なオーバーヘッドがなくなります。
パフォーマンス上の理由から、SQLExecute が呼び出されるまで、またはメタプロパティ操作 (ODBC の SQLDescribeCol、SQLDescribeParam など) が実行されるまで、ステートメントの準備は遅延されます。これは既定の動作です。準備されているステートメントのエラーは、ステートメントまたはメタプロパティ操作が実行されるまでわかりません。SQL Server Native Client ODBC ドライバ固有のステートメント属性の SQL_SOPT_SS_DEFER_PREPARE を SQL_DP_OFF に設定することで、この既定の動作を無効にできます。
準備が遅延されている場合、SQLExecute を呼び出す前に SQLDescribeCol または SQLDescribeParam のいずれかを呼び出すと、サーバーとの間に余分なやり取りが発生します。SQLDescribeCol では、クエリが返す最初の結果セットの列の情報を取得するために、ドライバはクエリから WHERE 句を削除し、SET FMTONLY ON を付加してサーバーに送信します。SQLDescribeParam では、クエリのすべてのパラメータ マーカーで参照される式や列の情報を取得するために、ドライバがサーバーを呼び出します。この方法には、サブクエリのパラメータを解決することができないなど、いくつか制限事項もあります。
SQL Server Native Client ODBC ドライバで SQLPrepare を使いすぎると、特に以前のバージョンの SQL Server に接続している場合はパフォーマンスが低下します。準備実行は、1 回しか実行されないステートメントには使用しないでください。準備実行では、クライアントからサーバーへのネットワーク上のやり取りを余分に実行する必要があるため、ステートメントを 1 回しか実行しない場合は直接実行よりも時間がかかります。以前のバージョンの SQL Server では、準備実行で一時ストアド プロシージャの生成も行います。
SQL Server 2000 以降、またはそれ以前のバージョンの SQL Server でも、ストアド プロシージャを生成するオプションがアクティブになっていると、一時オブジェクトを作成するために準備されたステートメントを使用することはできません。ストアド プロシージャを生成するオプションを有効にすると、SQLExecute が呼び出されるときに実行される一時ストアド プロシージャに、準備されたステートメントが組み込まれます。ストアド プロシージャの実行中に作成されるすべての一時オブジェクトは、プロシージャが終了するときに自動的に削除されます。次のどちらの例でも、ステートメントを準備する場合にストアド プロシージャを生成するオプションがアクティブであれば、一時テーブル #sometable が作成されないことになります。
SQLPrepare(hstmt,
"CREATE TABLE #sometable(cola int, colb char(8))",
SQL_NTS);
SQLExecute(hstmt);
または
SQLPrepare(hstmt,
"SELECT * FROM Authors INTO #sometable",
SQL_NTS);
SQLExecute(hstmt);
以前の ODBC アプリケーションでは、SQLBindParameter が使用されたときは必ず SQLPrepare を使用したものがありました。SQLBindParameter では、SQLPrepare を使用する必要はなく、SQLExecDirect と併用できます。たとえば、SQLBindParameter と SQLExecDirect を併用して、1 回しか実行されないストアド プロシージャからリターン コードや出力パラメータを取得します。同じステートメントが複数回実行される場合以外は、SQLBindParameter と SQLPrepare は併用しないでください。