次の方法で共有


複数のアクティブな結果セット (MARS) の使用

SQL Server 2005 では、データベース エンジンにアクセスするアプリケーションで複数のアクティブな結果セット (MARS) のサポートが導入されました。 以前のバージョンの SQL Server では、データベース アプリケーションは接続で複数のアクティブなステートメントを保持できませんでした。 SQL Server の既定の結果セットを使用する場合、アプリケーションは、その接続で他のバッチを実行する前に、1 つのバッチからすべての結果セットを処理または取り消す必要がありました。 SQL Server 2005 では、アプリケーションが接続ごとに複数の保留中の要求を持ち、特に接続ごとに複数のアクティブな既定の結果セットを使用できるようにする新しい接続属性が導入されました。

MARS は、次の新機能を使用してアプリケーションの設計を簡略化します。

  • アプリケーションでは、複数の既定の結果セットを開き、そこから読み取りをインターリーブできます。

  • 既定の結果セットが開いている間、アプリケーションは他のステートメント (INSERT、UPDATE、DELETE、ストアド プロシージャの呼び出しなど) を実行できます。

MARS を使用するアプリケーションでは、次のガイドラインが役立ちます。

  • 既定の結果セットは、単一の SQL ステートメント (SELECT、出力付き DML、RECEIVE、READ TEXT など) によって生成される有効期間の短い結果セットに使用する必要があります。

  • サーバー カーソルは、1 つの SQL ステートメントによって生成される有効期間が長い、または大きな結果セットに使用する必要があります。

  • 結果が返されるかどうかに関係なく、手続き型要求と、複数の結果を返すバッチについては、常に結果の最後まで読み取ります。

  • 可能な限り、API 呼び出しを使用して接続プロパティを変更し、Transact-SQL ステートメントを優先してトランザクションを管理します。

  • MARS では、同時バッチの実行中にセッション スコープの偽装が禁止されます。

既定では、MARS 機能は有効になっていません。 SQL Server Native Client を使用して SQL Server に接続するときに MARS を使用するには、接続文字列内で明示的に有効にする必要があります。 詳細については、このトピックで後述する「SQL Server Native Client OLE DB プロバイダー」および「SQL Server Native Client ODBC ドライバー」セクションを参照してください。

SQL Server Native Client では、接続上のアクティブなステートメントの数は制限されません。

複数のマルチステートメント バッチまたはストアド プロシージャを同時に実行する必要がない一般的なアプリケーションでは、MARS の実装方法を理解しなくても MARS のメリットが得られます。 ただし、より複雑な要件を持つアプリケーションでは、これを考慮する必要があります。

MARS を使用すると、1 つの接続内で複数の要求をインターリーブ実行できます。 つまり、バッチの実行が許可され、その実行中に他の要求を実行できるようになります。 ただし、MARS は、並列実行ではなく、インターリーブの観点から定義されていることに注意してください。

MARS インフラストラクチャでは、複数のバッチをインターリーブ形式で実行できますが、実行は適切に定義されたポイントでのみ切り替えることができます。 さらに、ほとんどのステートメントはバッチ内でアトミックに実行する必要があります。 クライアントに行を返すステートメント ( yield points と呼ばれることもあります) は、行がクライアントに送信されている間、完了前に実行をインターリーブできます。次に例を示します。

  • 選択する

  • フェッチ

  • 受ける

ストアド プロシージャまたはバッチの一部として実行されるその他のステートメントは、実行を他の MARS 要求に切り替える前に、完了するまで実行する必要があります。

バッチインターリーブ実行の正確な方法は、さまざまな要因の影響を受け、yield ポイントを含む複数のバッチからのコマンドが実行される正確なシーケンスを予測することは困難です。 このような複雑なバッチのインターリーブ実行による不要な副作用を避けるために注意してください。

接続状態 (SET、USE) とトランザクション (BEGIN TRAN、COMMIT、ROLLBACK) を管理するために、Transact-SQL ステートメントではなく API 呼び出しを使用して問題を回避します。これらのステートメントは、yield ポイントも含まれる複数のステートメント バッチに含めず、すべての結果を使用または取り消すことで、そのようなバッチの実行をシリアル化します。

MARS が有効な場合に手動または暗黙的なトランザクションを開始するバッチまたはストアド プロシージャは、バッチが終了する前にトランザクションを完了する必要があります。 そうでない場合、SQL Server は、バッチの終了時にトランザクションによって行われたすべての変更をロールバックします。 このようなトランザクションは、バッチ スコープ トランザクションとして SQL Server によって管理されます。 これは、SQL Server 2005 で導入された新しい種類のトランザクションで、MARS が有効な場合に既存の適切に動作するストアド プロシージャを使用できるようにします。 バッチ スコープ トランザクションの詳細については、「 トランザクション ステートメント (Transact-SQL)」を参照してください。

ADO からの MARS の使用例については、「 SQL Server Native Client での ADO の使用」を参照してください。

SQL Server Native Client OLE DB プロバイダー

SQL Server Native Client OLE DB プロバイダーは、DBPROPSET_SQLSERVERDBINIT プロパティ セットに実装されているSSPROP_INIT_MARSCONNECTION データ ソース初期化プロパティを追加して MARS をサポートします。 さらに、追加された新しい接続文字列キーワード MarsConntrue値またはfalse値を受け取ります。falseが既定値です。

データ ソース プロパティDBPROP_MULTIPLECONNECTIONS既定値は VARIANT_TRUE です。 つまり、複数の同時実行コマンド オブジェクトと行セット オブジェクトをサポートするために、プロバイダーは複数の接続を生成します。 MARS が有効になっている場合、SQL Server Native Client は 1 つの接続で複数のコマンド オブジェクトと行セット オブジェクトをサポートできるため、MULTIPLE_CONNECTIONSは既定でVARIANT_FALSEに設定されます。

DBPROPSET_SQLSERVERDBINIT プロパティ セットの機能強化の詳細については、「 初期化プロパティと承認プロパティ」を参照してください。

SQL Server Native Client OLE DB Provider の例

この例では、SQL Server Native OLE DB プロバイダーを使用してデータ ソース オブジェクトを作成し、セッション オブジェクトを作成する前に DBPROPSET_SQLSERVERDBINIT プロパティ セットを使用して MARS を有効にします。

#include <sqlncli.h>  
  
IDBInitialize *pIDBInitialize = NULL;  
IDBCreateSession *pIDBCreateSession = NULL;  
IDBProperties *pIDBProperties = NULL;  
  
// Create the data source object.  
hr = CoCreateInstance(CLSID_SQLNCLI10, NULL,  
   CLSCTX_INPROC_SERVER,  
   IID_IDBInitialize,   
    (void**)&pIDBInitialize);  
  
hr = pIDBInitialize->QueryInterface(IID_IDBProperties, (void**)&pIDBProperties);  
  
// Set the MARS property.  
DBPROP rgPropMARS;  
  
// The following is necessary since MARS is off by default.  
rgPropMARS.dwPropertyID = SSPROP_INIT_MARSCONNECTION;  
rgPropMARS.dwOptions = DBPROPOPTIONS_REQUIRED;  
rgPropMARS.dwStatus = DBPROPSTATUS_OK;  
rgPropMARS.colid = DB_NULLID;  
V_VT(&(rgPropMARS.vValue)) = VT_BOOL;  
V_BOOL(&(rgPropMARS.vValue)) = VARIANT_TRUE;  
  
// Create the structure containing the properties.  
DBPROPSET PropSet;  
PropSet.rgProperties = &rgPropMARS;  
PropSet.cProperties = 1;  
PropSet.guidPropertySet = DBPROPSET_SQLSERVERDBINIT;  
  
// Get an IDBProperties pointer and set the initialization properties.  
pIDBProperties->SetProperties(1, &PropSet);  
pIDBProperties->Release();  
  
// Initialize the data source object.  
hr = pIDBInitialize->Initialize();  
  
//Create a session object from a data source object.  
IOpenRowset * pIOpenRowset = NULL;  
hr = IDBInitialize->QueryInterface(IID_IDBCreateSession, (void**)&pIDBCreateSession));  
hr = pIDBCreateSession->CreateSession(  
   NULL,             // pUnkOuter  
   IID_IOpenRowset,  // riid  
  &pIOpenRowset ));  // ppSession  
  
// Create a rowset with a firehose mode cursor.  
IRowset *pIRowset = NULL;  
DBPROP rgRowsetProperties[2];  
  
// To get a firehose mode cursor request a   
// forward only read only rowset.  
rgRowsetProperties[0].dwPropertyID = DBPROP_IRowsetLocate;  
rgRowsetProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;  
rgRowsetProperties[0].dwStatus = DBPROPSTATUS_OK;  
rgRowsetProperties[0].colid = DB_NULLID;  
VariantInit(&(rgRowsetProperties[0].vValue));  
rgRowsetProperties[0].vValue.vt = VARIANT_BOOL;  
rgRowsetProperties[0].vValue.boolVal = VARIANT_FALSE;  
  
rgRowsetProperties[1].dwPropertyID = DBPROP_IRowsetChange;  
rgRowsetProperties[1].dwOptions = DBPROPOPTIONS_REQUIRED;  
rgRowsetProperties[1].dwStatus = DBPROPSTATUS_OK;  
rgRowsetProperties[1].colid = DB_NULLID;  
VariantInit(&(rgRowsetProperties[1].vValue));  
rgRowsetProperties[1].vValue.vt = VARIANT_BOOL;  
rgRowsetProperties[1].vValue.boolVal = VARIANT_FALSE;  
  
DBPROPSET rgRowsetPropSet[1];  
rgRowsetPropSet[0].rgProperties = rgRowsetProperties  
rgRowsetPropSet[0].cProperties = 2  
rgRowsetPropSet[0].guidPropertySet = DBPROPSET_ROWSET;  
  
hr = pIOpenRowset->OpenRowset (NULL,  
   &TableID,  
   NULL,  
   IID_IRowset,  
   1,  
   rgRowsetPropSet  
   (IUnknown**)&pIRowset);  

SQL Server Native Client ODBC ドライバー

SQL Server Native Client ODBC ドライバーは、SQLSetConnectAttr 関数と SQLGetConnectAttr 関数に追加して MARS をサポートします。 SQL_COPT_SS_MARS_ENABLEDは、SQL_MARS_ENABLED_YESまたはSQL_MARS_ENABLED_NOを受け入れるように追加されており、SQL_MARS_ENABLED_NOが既定値です。 さらに、追加された新しい接続文字列キーワード Mars_Connection。 "yes" または "no" の値を受け入れます。既定値は "no" です。

SQL Server Native Client ODBC ドライバーの例

この例では、 SQLSetConnectAttr 関数を使用して MARS を有効にしてから 、SQLDriverConnect 関数を 呼び出してデータベースを接続します。 接続が確立されると、2 つの SQLExecDirect 関数が呼び出され、同じ接続に 2 つの個別の結果セットが作成されます。

#include <sqlncli.h>  
  
SQLSetConnectAttr(hdbc, SQL_COPT_SS_MARS_ENABLED, SQL_MARS_ENABLED_YES, SQL_IS_UINTEGER);  
SQLDriverConnect(hdbc, hwnd,   
   "DRIVER=SQL Server Native Client 10.0;  
   SERVER=(local);trusted_connection=yes;", SQL_NTS, szOutConn,   
   MAX_CONN_OUT, &cbOutConn, SQL_DRIVER_COMPLETE);  
  
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt1);  
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt2);  
  
// The 2nd execute would have failed with connection busy error if  
// MARS were not enabled.  
SQLExecDirect(hstmt1, L"SELECT * FROM Authors", SQL_NTS);  
SQLExecDirect(hstmt2, L"SELECT * FROM Titles", SQL_NTS);  
  
// Result set processing can interleave.  
SQLFetch(hstmt1);  
SQLFetch(hstmt2);  

こちらもご覧ください

SQL Server Native Client の機能
SQL Server の既定の結果セットの使用