使用 Multiple Active Result Sets (MARS)
SQL Server 2005 在存取 Database Engine 的應用程式中導入了對 Multiple Active Result Sets (MARS) 的支援。在舊版的 SQL Server 中,資料庫應用程式無法在連接上維護多個作用中陳述式。當使用 SQL Server 預設結果集時,應用程式必須從一個批次處理或取消所有結果集,然後才能夠在該連接上執行任何其他批次。SQL Server 2005 導入了新的連接屬性,讓應用程式在每個連接上可以有一個以上的暫止要求,而且特別是每個連接上可以有一個以上的使用中預設結果集。
MARS 會使用以下的新功能來簡化應用程式設計:
應用程式可以開啟多個預設結果集,而且可以交錯讀取這些結果集。
當開啟預設結果集時,應用程式可以執行其他陳述式 (例如 INSERT、UPDATE、DELETE 和預存程序呼叫)。
以下的指導方針對於使用 MARS 的應用程式非常有用:
預設結果集應該用於單一 SQL 陳述式 (SELECT、DML with OUTPUT、RECEIVE、READ TEXT 等等) 所產生的短期或簡短結果集。
伺服器資料指標應該用於單一 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 可啟用單一連接內多個要求的交錯執行。也就是說,它可允許批次執行,而且當它執行時,可允許其他要求執行。但是請注意,MARS 是以交錯來定義,而不是以平行執行來定義。
MARS 基礎結構可讓多個批次以交錯方式執行,但是只能在定義良好的點上切換執行。此外,大多數的陳述式都必須在批次內自動執行。當資料列傳送給用戶端時,允許在完成以前交錯執行傳回資料列給用戶端的陳述式 (有時也稱為產生點),例如:
SELECT
FETCH
RECEIVE
當執行可以切換到其他 MARS 要求之前,當做預存程序或批次的一部分執行的其他任何陳述式都必須執行到完成為止。
批次交錯執行的確切方式會受到一些因素的影響,而且很難預測包含產生點之多個批次中將要執行命令的確切順序。請小心避免因為這類複雜批次的交錯執行所產生之不必要的副作用。
若要避免問題的發生,請使用 API 呼叫 (而非 Transact-SQL 陳述式) 來管理連接狀態 (SET、USE) 和交易 (BEGIN TRAN、COMMIT、ROLLBACK),其方式是不要將這些陳述式併入同樣包含產生點的多重陳述式批次內,以及取用或取消所有結果來序列化這類批次的執行。
[!附註]
在啟用 MARS 時啟動手動或隱含交易的批次或預存程序必須先完成交易,然後才能結束批次。如果不是這樣的話,SQL Server 會在批次完成時回復交易所做的所有變更。這類交易是由 SQL Server 當做批次範圍的交易來管理。SQL Server 2005 中導入了新類型的交易,好讓現有行為良好的預存程序在啟用 MARS 時可以使用。如需有關批次範圍交易的詳細資訊,請參閱<交易陳述式 (Transact-SQL)>和<控制交易 (Database Engine)>。
如需從 ADO 使用 MARS 的範例,請參閱<使用 ADO 搭配 SQL Server Native Client>。
SQL Server Native Client OLE DB 提供者
SQL Server Native Client OLE DB 提供者可透過 SSPROP_INIT_MARSCONNECTION 資料來源初始化屬性的加入來支援 MARS,該屬性是在 DBPROPSET_SQLSERVERDBINIT 屬性集中實作。此外,也已經加入新的連接字串關鍵字 MarsConn。它可接受 true 或 false 值;false 是預設值。
資料來源屬性 DBPROP_MULTIPLECONNECTIONS 預設為 VARIANT_TRUE。這表示,為了支援多個並行命令和資料列集物件,此提供者將會繁衍多個連接。當啟用 MARS 時,SQL Server Native Client 可在單一連接上支援多個命令和資料列集物件,好讓 MULTIPLE_CONNECTIONS 預設為 VARIANT_FALSE。
如需有關對 DBPROPSET_SQLSERVERDBINIT 屬性集所做之增強的詳細資訊,請參閱<初始化和授權屬性>。
SQL Server Native Client OLE DB 提供者範例
此範例中會使用 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 驅動程式範例
在此範例中,在呼叫 SQLDriverConnect 函數來連接資料庫以前會使用 SQLSetConnectAttr 函數來啟用 MARS。一旦進行連接以後,就會呼叫兩個 SQLExecDirect 函數,在相同連接上建立兩個不同的結果集。
#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);