使用 Multiple Active Result Sets (MARS)
SQL Server 2005 引進了多個作用中結果集的支援, (MARS) 存取 Database Engine 的應用程式。 在舊版的 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)。
如需從 ADO 使用 MARS 的範例,請參閱搭配使用 ADO 搭配SQL Server Native Client。
SQL Server Native Client OLE DB 提供者
SQL Server Native Client OLE DB 提供者透過新增在 DBPROPSET_SQLSERVERDBINIT 屬性集中實作的SSPROP_INIT_MARSCONNECTION資料來源初始化屬性,支援 MARS。 此外,也已經加入新的連接字串關鍵字 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 提供者所建立,而 MARS 則會使用建立會話物件之前所設定的 DBPROPSET_SQLSERVERDBINIT 屬性來啟用。
#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 函式來連接資料庫。 建立連接之後,會呼叫兩個 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);