Verwenden von Multiple Active Result Sets (MARS).

Seit SQL Server 2005 werden Multiple Active Result Sets (MARS) in Anwendungen unterstützt, die auf Database Engine (Datenbankmodul) zugreifen. In früheren Versionen von SQL Server konnten Datenbankanwendungen nicht mehrere aktive Anweisungen über eine Verbindung verwalten. Bei Verwendung des SQL Server-Standardresultsets musste die Anwendung alle Resultsets aus einem Batch verarbeiten oder abbrechen, ehe sie einen anderen Batch über diese Verbindung ausführen konnte. In SQL Server 2005 wurde ein neues Verbindungsattribut eingeführt, mit dem Anwendungen mehrere anstehende Anforderungen und insbesondere mehrere aktive Standardresultsets pro Verbindung haben können.

MARS vereinfacht den Anwendungsentwurf mit den folgenden neuen Fähigkeiten:

  • Anwendungen können mehrere Standardresultsets geöffnet haben und die Lesevorgänge daraus verschachteln.

  • Anwendungen können bei geöffneten Standardresultsets andere Anweisungen ausführen (z. B. INSERT, UPDATE, DELETE und Aufrufe gespeicherter Prozeduren).

Für Anwendungen, die MARS verwenden, gelten die folgenden nützlichen Richtlinien:

  • Standardresultsets sollten für kurzlebige oder kurze Resultsets verwendet werden, die durch einzelne SQL-Anweisungen generiert werden (SELECT, DML mit OUTPUT, RECEIVE, READ TEXT usw.).

  • Servercursor sollten für längerlebige oder große Resultsets verwendet werden, die durch einzelne SQL-Anweisungen generierte werden.

  • Lesen Sie bei Batches, die mehrere Ergebnisse zurückgeben, und bei Prozeduranforderungen immer bis zum Ende der Results, unabhängig davon, ob Ergebnisse zurückgeben werden oder nicht.

  • Wo möglich, verwenden Sie anstelle von Transact-SQL-Anweisungen API-Aufrufe, um Verbindungseigenschaften zu ändern und Transaktionen zu verwalten.

  • In MARS wird ein Identitätswechsel im Bereich einer Sitzung verhindert, solange gleichzeitige Batches ausgeführt werden.

HinweisHinweis

Standardmäßig ist die MARS-Funktionalität nicht aktiviert. Um MARS bei der Verbindung mit SQL Server über SQL Server Native Client zu verwenden, müssen Sie die Funktionalität in einer Verbindungszeichenfolge explizit aktivieren. Weitere Informationen finden Sie in den Abschnitten zum OLE DB-Anbieter von SQL Server Native Client und dem SQL Server Native Client-ODBC-Treiber im weiteren Verlauf dieses Themas.

Bei SQL Server Native Client gilt keine Beschränkung der Anzahl der aktiven Anweisungen für eine Verbindung.

Typische Anwendungen, bei denen kein Bedarf für mehrere Batches oder gespeicherte Prozeduren aus mehreren gleichzeitig ausgeführten Anweisungen besteht, profitieren von MARS, ohne die Implementierung von MARS verstehen zu müssen. Anwendungen mit komplexeren Anforderungen müssen diese jedoch berücksichtigen.

MARS ermöglicht die verschachtelte Ausführung mehrerer Anforderungen innerhalb einer einzelnen Verbindung. Das bedeutet, dass innerhalb der Ausführung eines Batches eine weitere Anforderung ausgeführt werden kann. Beachten Sie jedoch, dass MARS mit Blick auf Interleaving, nicht die parallele Ausführung definiert ist.

Die MARS-Infrastruktur ermöglicht die verschachtelte Ausführung mehrerer Batches, die Ausführung kann jedoch nur an genau definierten Punkten gewechselt werden. Außerdem müssen die meisten Anweisungen innerhalb eines Batches atomar ausgeführt werden. Anweisungen, die Zeilen an den Client zurückgeben (gelegentlich bezeichnet als Zwischenergebnispunkte) dürfen die Ausführung vor Abschluss verschachteln, während noch Zeilen an den Client gesendet werden. Beispiel:

  • SELECT

  • FETCH

  • RECEIVE

Alle anderen Anweisungen, die im Rahmen einer gespeicherten Prozedur oder eines Batches ausgeführt werden, müssen zunächst abgeschlossen werden, ehe die Ausführung zu anderen MARS-Anforderungen umgeschaltet werden kann.

Wie Batches die Ausführung genau verschachteln, hängt von zahlreichen Faktoren ab, und die exakte Ausführungsfolge von Befehlen aus mehreren Batches mit Zwischenergebnispunkten lässt sich nur schwer vorhersagen. Achten Sie darauf, unerwünschte Nebeneffekte aufgrund der verschachtelten Ausführung solcher komplexer Batches zu vermeiden.

Sie vermeiden Probleme, indem Sie den Verbindungsstatus (SET, USE) und Transaktionen (BEGIN TRAN, COMMIT, ROLLBACK) an Stelle von Transact-SQL-Anweisungen mit API-Aufrufen verwalten. Schließen Sie diese Anweisungen zudem nicht in Batches mit mehreren Anweisungen ein, die auch Zwischenergebnispunkte enthalten, und serialisieren Sie die Ausführung solcher Batches durch Verarbeitung oder Abbruch aller Ergebnisse.

HinweisHinweis

Ein Batch oder eine gespeicherte Prozedur, die bei Aktivierung von MARS eine manuelle oder implizite Transaktion startet, muss diese Transaktion vor Ausführung des Batchs abschließen. Andernfalls führt SQL Server nach Abschluss des Batchs einen Rollback für alle von der Transaktion vorgenommenen Änderungen aus. Eine derartige Transaktion wird von SQL Server als Transaktion im Bereich des Batchs verwaltet. Dieser Transaktionstyp wurde in SQL Server 2005 neu eingeführt, um vorhandene, gut konzipierte gespeicherte Prozeduren verwenden zu können, wenn MARS aktiviert ist. Weitere Informationen über Transaktionen im Batchbereich finden Sie unter Transaktionsanweisungen (Transact-SQL) und Steuern von Transaktionen (Datenbankmodul).

Ein Beispiel für das Verwenden von MARS aus ADO finden Sie unter Verwenden von ADO mit SQL Server Native Client.

OLE DB-Anbieter von SQL Server Native Client

Der OLE DB-Anbieter von SQL Server Native Client unterstützt MARS durch Hinzufügen der SSPROP_INIT_MARSCONNECTION-Eigenschaft zur Datenquelleninitialisierung, die in der Eigenschaftengruppe DBPROPSET_SQLSERVERDBINIT implementiert wird. Außerdem wurde ein neues Verbindungszeichenfolgen-Schlüsselwort aufgenommen, MarsConn. Gültige Werte sind true oder false; der Standardwert ist false.

Die Datenquelleneigenschaft DBPROP_MULTIPLECONNECTIONS ist standardmäßig auf VARIANT_TRUE festgelegt. Das bedeutet, der Anbieter erzeugt mehrere Verbindungen, um mehrere gleichzeitige Befehls- und Rowsetobjekte zu unterstützen. Ist MARS aktiviert, kannSQL Server Native Client mehrere Befehls- und Rowsetobjekte in einer einzelnen Verbindung unterstützen. Daher ist MULTIPLE_CONNECTIONS standardmäßig auf VARIANT_FALSE festgelegt.

Weitere Informationen zu Verbesserungen an der DBPROPSET_SQLSERVERDBINIT-Eigenschaftengruppe finden Sie unter Initialisierungs- und Autorisierungseigenschaften.

OLE DB-Anbieter von SQL Server Native Client: Beispiel

In diesem Beispiel wird mit dem OLE DB-Anbieter von SQL Server Native Client ein Datenquellenobjekt erstellt. Vor der Erstellung des Sitzungsobjekts wird MARS mithilfe der DBPROPSET_SQLSERVERDBINIT-Eigenschaftengruppe aktiviert.

#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-Treiber

Der SQL Server Native Client-ODBC-Treiber unterstützt MARS durch Hinzufügungen zu den Funktionen SQLSetConnectAttr und SQLGetConnectAttr. SQL_COPT_SS_MARS_ENABLED wurde hinzugefügt, um entweder SQL_MARS_ENABLED_YES oder SQL_MARS_ENABLED_NO zu akzeptieren. Der Standardwert ist SQL_MARS_ENABLED_NO. Außerdem wurde ein neues Verbindungszeichenfolgen-Schlüsselwort aufgenommen, Mars_Connection. Gültige Werte sind "Ja" oder "Nein", wobei "Nein" die Standardeinstellung ist.

SQL Server Native Client-ODBC-Treiber: Beispiel

In diesem Beispiel wird MARS mithilfe der SQLSetConnectAttr-Funktion aktiviert. Anschließend wird die SQLDriverConnect-Funktion aufgerufen, um die Verbindung zur Datenbank herzustellen. Im Anschluss daran werden zwei SQLExecDirect-Funktionen aufgerufen, um zwei gesonderte Resultsets für dieselbe Verbindung zu erstellen.

#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);