Delen via


Meerdere actieve resultatensets (MARS) gebruiken

Van toepassing op:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceAzure Synapse AnalyticsAnalytics Platform Systeem (PDW)SQL-database in Microsoft Fabric

OLE DB-stuurprogramma downloaden

SQL Server 2005 (9.x) introduceerde ondersteuning voor meerdere actieve resultaatsets (MARS) in applicaties die toegang hadden tot de Database Engine. In eerdere versies van SQL Server konden databaseapplicaties geen meerdere actieve statements op een verbinding onderhouden. Bij het gebruik van standaard resultaten in SQL Server moest de applicatie alle resultaatsets van één batch verwerken of annuleren voordat een andere batch op die verbinding kon worden uitgevoerd. SQL Server 2005 (9.x) introduceerde een nieuw verbindingsattribuut waarmee applicaties meer dan één wachtend verzoek per verbinding kunnen hebben, en in het bijzonder om meer dan één actieve standaardresultaat per verbinding te laten instellen.

MARS vereenvoudigt applicatieontwerp met de volgende nieuwe mogelijkheden:

  • Applicaties kunnen meerdere standaard resultaatsets open hebben en kunnen lezen uit deze door elkaar veroverd.

  • Applicaties kunnen andere statements uitvoeren (bijvoorbeeld INSERT, UPDATE, DELETE en stored procedure calls) terwijl standaardresultatensets open zijn.

Applicaties die MARS gebruiken, zullen de volgende richtlijnen nuttig vinden:

  • Standaard resultaatsets moeten worden gebruikt voor kortstondige of korte resultaatsets die worden gegenereerd door enkele SQL-instructies (SELECT, DML met OUTPUT, RECEIVE, READ TEXT, enzovoort).

  • Servercursors moeten worden gebruikt voor langere of grote resultatensets die worden gegenereerd door enkele SQL-instructies.

  • Lees altijd het einde van resultaten voor procedurele verzoeken, ongeacht of ze resultaten teruggeven of niet, en voor batches die meerdere resultaten teruggeven.

  • Gebruik waar mogelijk API-aanroepen om verbindingseigenschappen te wijzigen en transacties te beheren in plaats van Transact-SQL statements.

  • In MARS is session-scoped imitatie verboden terwijl gelijktijdige batches draaien.

Opmerking

Standaard is MARS-functionaliteit niet ingeschakeld. Om MARS te gebruiken bij het verbinden met SQL Server met OLE DB Driver voor SQL Server, moet je het specifiek inschakelen binnen een verbindingsstring. Voor meer informatie, zie de secties OLE DB Driver for SQL Server, later in dit onderwerp.

OLE DB Driver voor SQL Server beperkt het aantal actieve statements op een verbinding niet.

Typische applicaties die niet meer dan één multistatement batch of opgeslagen procedure tegelijk hoeven uitvoeren, profiteren van MARS zonder te hoeven begrijpen hoe MARS wordt geïmplementeerd. Toepassingen met complexere vereisten moeten hier echter rekening mee houden.

MARS maakt de interlaced uitvoering van meerdere verzoeken binnen één verbinding mogelijk. Dat wil zeggen, het laat een batch draaien, en tijdens de uitvoering ervan laat het andere verzoeken uitvoeren. Let echter op dat MARS wordt gedefinieerd in termen van interleaving, niet in termen van parallelle uitvoering.

De MARS-infrastructuur maakt het mogelijk dat meerdere batches op interleaved wijze kunnen worden uitgevoerd, hoewel de uitvoering alleen op goed gedefinieerde punten kan worden geschakeld. Daarnaast moeten de meeste statements atomair binnen een batch draaien. Statements die rijen teruggeven aan de client, die soms yield points worden genoemd, mogen uitvoering interleaven voordat ze voltooid zijn terwijl rijen naar de client worden gestuurd, bijvoorbeeld:

  • SELECT

  • FETCH

  • RECEIVE

Alle andere statements die worden uitgevoerd als onderdeel van een opgeslagen procedure of batch moeten volledig worden uitgevoerd voordat uitvoering kan worden overgeschakeld naar andere MARS-verzoeken.

De exacte manier waarop batch-interleave-uitvoering wordt beïnvloed door een aantal factoren, en het is moeilijk om de exacte volgorde te voorspellen waarin commando's van meerdere batches met yield points zullen worden uitgevoerd. Wees voorzichtig om ongewenste bijwerkingen te vermijden door de interleaved uitvoering van zulke complexe batches.

Vermijd problemen door API-aanroepen te gebruiken in plaats van Transact-SQL statements om de verbindingstoestand (SET, USE) en transacties (BEGIN TRAN, COMMIT, ROLLBACK) te beheren door deze statements niet op te nemen in multi-statement batches die ook yield points bevatten, en door de uitvoering van dergelijke batches te serialiseren door alle resultaten te consumeren of te annuleren.

Opmerking

Een batch- of opgeslagen procedure die een handmatige of impliciete transactie start wanneer MARS wordt ingeschakeld, moet de transactie voltooien voordat de batch wordt afgesloten. Als dat niet gebeurt, rolt SQL Server alle wijzigingen die door de transactie zijn aangebracht terug zodra de batch is afgerond. Zo'n transactie wordt door SQL Server beheerd als een batch-scoped transactie. Dit is een nieuw type transactie dat in SQL Server 2005 (9.x) is geïntroduceerd om bestaande goed gedragen opgeslagen procedures te kunnen gebruiken wanneer MARS is ingeschakeld. Voor meer informatie over batch-scoped transacties, zie Transaction Statements (Transact-SQL).

Voor een voorbeeld van het gebruik van MARS vanuit ADO, zie Gebruik ADO met OLE DB Driver voor SQL Server.

OLTP In-Memory

OLTP ondersteunt MARS met queries en native gecompileerde opgeslagen procedures. MARS maakt het mogelijk om gegevens van meerdere queries op te vragen zonder dat je elke resultaatset volledig hoeft op te halen voordat een verzoek wordt gestuurd om rijen uit een nieuwe resultaatset op te halen. Om succesvol uit meerdere open resultaatsets te lezen, moet je een MARS-geactiveerde verbinding gebruiken.

MARS is standaard uitgeschakeld, dus je moet het expliciet inschakelen door toe te voegen MultipleActiveResultSets=True aan een verbindingsstring. Het volgende voorbeeld laat zien hoe je verbinding maakt met een instantie van SQL Server en aangeeft dat MARS is ingeschakeld:

Data Source=MSSQL; Initial Catalog=AdventureWorks; Integrated Security=SSPI; MultipleActiveResultSets=True  

MARS met In-Memory OLTP is in wezen hetzelfde als MARS in de rest van de SQL-engine. Het volgende geeft een overzicht van de verschillen bij het gebruik van MARS in geheugengeoptimaliseerde tabellen en native gecompileerde opgeslagen procedures.

MARS- en geheugengeoptimaliseerde tabellen

De volgende verschillen tussen schijfgebaseerde en geheugengeoptimaliseerde tabellen bij gebruik van een MARS-geschikte verbinding:

  • Twee statements kunnen data wijzigen in hetzelfde doelobject, maar als ze allebei proberen hetzelfde record te wijzigen, zal een schrijf-schrijfconflict ervoor zorgen dat de nieuwe bewerking mislukt. Als beide bewerkingen echter verschillende records wijzigen, slagen de bewerkingen.

  • Elke instructie draait onder SNAPSHOT-isolatie, zodat nieuwe bewerkingen de wijzigingen van bestaande statements niet kunnen zien. Zelfs als de gelijktijdige statements onder dezelfde transactie worden uitgevoerd, maakt de SQL-engine batch-scoped transacties voor elke instructie die van elkaar geïsoleerd zijn. Echter, batch-scoped transacties blijven aan elkaar gebonden, dus het terugdraaien van één batch-scoped transactie beïnvloedt andere transacties in dezelfde batch.

  • DDL-bewerkingen zijn niet toegestaan in gebruikerstransacties, dus ze zullen direct falen.

MARS en native gecompileerde opgeslagen procedures

Native gecompileerde opgeslagen procedures kunnen draaien in MARS-enabled verbindingen en kunnen alleen uitvoering geven aan een andere instructie wanneer een yield point wordt gevonden. Een yield point vereist een SELECT-statement, die de enige statement is binnen een native gecompileerde stored procedure die uitvoering kan geven aan een andere statement. Als er geen SELECT-instructie aanwezig is in de procedure die deze niet oplevert, zal deze tot voltooiing draaien voordat andere statements beginnen.

MARS- en in-memory OLTP-transacties

Wijzigingen die door statements en atomaire blokken worden aangebracht die met elkaar verveven zijn, worden van elkaar geïsoleerd. Als bijvoorbeeld één statement of atomic block enkele wijzigingen aanbrengt en vervolgens uitvoering geeft aan een andere statement, zal de nieuwe statement geen wijzigingen zien die door de eerste statement zijn gemaakt. Bovendien zal de eerste instructie bij hervatting van de uitvoering geen wijzigingen zien die door andere instructies zijn aangebracht. Statements zien alleen wijzigingen die zijn afgerond en uitgevoerd voordat de verklaring begint.

Een nieuwe gebruikerstransactie kan binnen de huidige gebruikerstransactie worden gestart met de BEGIN TRANSACTION-instructie - dit wordt alleen ondersteund in interoperabiliteitsmodus, dus de BEGIN TRANSACTION kan alleen worden aangeroepen vanuit een T-SQL-instructie, en niet vanuit een native gecompileerde opgeslagen procedure. Je kunt een save point maken in een transactie met SAVE TRANSACTION of een API-aanroep naar transactie. Save(save_point_name) om terug te rollen naar het savepoint. Deze functie wordt ook alleen ingeschakeld vanuit T-SQL-instructies, en niet vanuit native gecompileerde opgeslagen procedures.

MARS- en columnstore-indexen

SQL Server (vanaf 2016) ondersteunt MARS met columnstore-indexen. SQL Server 2014 gebruikt MARS voor alleen-lezen verbindingen met tabellen met een columnstore-index. SQL Server 2014 ondersteunt echter geen MARS voor gelijktijdige data manipulation language (DML)-operaties op een tabel met een kolomopslagindex. Wanneer dit gebeurt, zal SQL Server de verbindingen beëindigen en de transacties afbreken. SQL Server 2012 heeft alleen-lezen kolomopslagindexen en MARS is daar niet op van toepassing.

OLE DB-stuurprogramma voor SQL Server

De OLE DB Driver voor SQL Server ondersteunt MARS door de toevoeging van de eigenschap SSPROP_INIT_MARSCONNECTION databroninitialisatie, die is geïmplementeerd in de DBPROPSET_SQLSERVERDBINIT property set. Daarnaast is er een nieuw verbindingsstring-sleutelwoord toegevoegd, MarsConn. Het accepteert ware of onwaarse waarden; False is de standaard.

De eigenschap van de gegevensbron DBPROP_MULTIPLECONNECTIONS standaard op VARIANT_TRUE. Dit betekent dat de provider meerdere verbindingen zal opzetten om meerdere gelijktijdige commando- en rowset-objecten te ondersteunen. Wanneer MARS is ingeschakeld, kan OLE DB Driver for SQL Server meerdere commando- en rowset-objecten op één verbinding ondersteunen, dus MULTIPLE_CONNECTIONS standaard op VARIANT_FALSE staat.

Voor meer informatie over verbeteringen aan de DBPROPSET_SQLSERVERDBINIT eigenschapsset, zie Initialisatie- en Autorisatie-eigenschappen.

OLE DB-driver voor SQL Server voorbeeld

In dit voorbeeld wordt een databronobject gemaakt met de OLE DB Driver voor SQL Server, en wordt MARS ingeschakeld met de DBPROPSET_SQLSERVERDBINIT property set voordat het sessieobject wordt aangemaakt.

#include <msoledbsql.h>  
  
IDBInitialize *pIDBInitialize = NULL;  
IDBCreateSession *pIDBCreateSession = NULL;  
IDBProperties *pIDBProperties = NULL;  
  
// Create the data source object.  
hr = CoCreateInstance(CLSID_MSOLEDBSQL, 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);  

Zie ook

OLE DB-driver voor SQL Server-functies