Användning av flera aktiva resultatuppsättningar (MARS) i SQL Server Native Client

gäller för:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceAzure Synapse AnalyticsAnalytics Platform System (PDW)

Important

SQL Server Native Client (SNAC) levereras inte med:

  • SQL Server 2022 (16.x) och senare versioner
  • SQL Server Management Studio 19 och senare versioner

SQL Server Native Client (SQLNCLI eller SQLNCLI11) och den äldre Microsoft OLE DB-providern för SQL Server (SQLOLEDB) rekommenderas inte för ny programutveckling.

Använd någon av följande drivrutiner för nya projekt:

För SQLNCLI som levereras som en komponent i SQL Server-databasmotorn (versioner 2012 till och med 2019), se det här Support Lifecycle-undantag.

SQL Server 2005 (9.x) introducerade stöd för flera aktiva resultatuppsättningar (MARS) i applikationer som använder databasmotorn. I tidigare versioner av SQL Server kunde databasapplikationer inte underhålla flera aktiva satser på en anslutning. När SQL Server-standardresultatuppsättningar användes var applikationen tvungen att bearbeta eller avbryta alla resultatuppsättningar från en batch innan den kunde köra någon annan batch på den anslutningen. SQL Server 2005 (9.x) introducerade ett nytt anslutningsattribut som tillåter applikationer att ha mer än en väntande förfrågan per anslutning, och särskilt att ha mer än ett aktivt standardresultat inställt per anslutning.

MARS förenklar applikationsdesign med följande nya funktioner:

  • Applikationer kan ha flera standardresultatuppsättningar öppna och kan interleaving läsa från dem.

  • Applikationer kan köra andra satser (till exempel INSERT, UPDATE, DELETE, och anrop av lagrade procedurer) medan standardresultatuppsättningar är öppna.

Applikationer som använder MARS kommer att finna följande riktlinjer fördelaktiga:

  • Standardresultatuppsättningar bör användas för kortlivade eller korta resultatuppsättningar genererade av enskilda SQL-satser (SELECT, DML med OUTPUT, RECEIVE, READ TEXT och så vidare).

  • Servermarkörer bör användas för långlivade eller stora resultatuppsättningar som genereras av enskilda SQL-satser.

  • Läs alltid till slutet av resultat för procedurförfrågningar oavsett om de returnerar resultat eller inte, och för batcher som ger flera resultat.

  • Använd där det är möjligt API-anrop för att ändra anslutningsegenskaper och hantera transaktioner istället för Transact-SQL satser.

  • I MARS är session-scoped imitation förbjuden medan samtidiga batcher körs.

Not

Som standard aktiveras inte MARS-funktionaliteten av drivrutinen. För att använda MARS när du ansluter till SQL Server med SQL Server Native Client måste du specifikt aktivera MARS inom en reťazec pripojenia. Dock kan vissa applikationer aktivera MARS som standard, om applikationen upptäcker att drivrutinen stöder MARS. För dessa applikationer kan du inaktivera MARS i reťazec pripojenia vid behov. För mer information, se avsnitten SQL Server Native Client OLE DB-leverantör och SQL Server Native Client ODBC-drivrutiner, senare i detta ämne.

SQL Server Native Client begränsar inte antalet aktiva satser på en anslutning.

Typiska applikationer som inte behöver ha mer än en enda batch med flera uttalanden eller lagrad procedur som körs samtidigt kommer att dra nytta av MARS utan att behöva förstå hur MARS implementeras. Dock måste applikationer med mer komplexa krav ta hänsyn till detta.

MARS möjliggör interflettad exekvering av flera förfrågningar inom en enda anslutning. Det vill säga, den tillåter en batch att köras, och under dess exekvering tillåter den andra förfrågningar att exekveras. Observera dock att MARS definieras i termer av interleaving, inte i termer av parallell exekvering.

MARS-infrastrukturen tillåter att flera batcher kan köras på ett interleaved sätt, även om exekveringen endast kan växlas vid väl definierade punkter. Dessutom måste de flesta satser köras atomärt inom en batch. Satser som returnerar rader till klienten, som ibland kallas yield points, får interleave-exekveras innan de är klara medan rader skickas till klienten, till exempel:

  • SELECT

  • FETCH

  • RECEIVE

Alla andra satser som körs som en del av en lagrad procedur eller batch måste köras till slut innan exekveringen kan bytas till andra MARS-förfrågningar.

Det exakta sättet på vilket batch-interleave-utförandet påverkas av flera faktorer, och det är svårt att förutsäga den exakta ordningen i vilken kommandon från flera batcher som innehåller yield points kommer att utföras. Var försiktig så att du undviker oönskade biverkningar på grund av sammanflätad utförande av så komplexa batcher.

Undvik problem genom att använda API-anrop istället för Transact-SQL satser för att hantera anslutningstillstånd (SET, USE) och transaktioner (BEGIN TRAN, COMMIT, ROLLBACK) genom att inte inkludera dessa satser i multi-statement batcher som också innehåller yield points, och genom att serialisera exekveringen av sådana batcher genom att konsumera eller avbryta alla resultat.

Not

En batch- eller lagrad procedur som startar en manuell eller implicit transaktion när MARS aktiveras måste slutföra transaktionen innan batchen avslutas. Om det inte gör det, rullar SQL Server tillbaka alla ändringar som gjorts av transaktionen när batchen är klar. En sådan transaktion hanteras av SQL Server som en batch-scoped transaktion. Detta är en ny typ av transaktion som introducerades i SQL Server 2005 (9.x) för att möjliggöra användning av befintliga väluppförda lagrade procedurer när MARS är aktiverat. För mer information om batch-scoped transaktioner, se Transaction Statements (Transact-SQL).

För ett exempel på att använda MARS från ADO, se Using ADO with SQL Server Native Client.

Minnesbaserad OLTP

In-memory OLTP stöder MARS med hjälp av frågor och nativt kompilerade lagrade procedurer. MARS möjliggör att begära data från flera frågor utan att behöva hämta varje resultatmängd helt innan en begäran om rader från en ny resultatuppsättning skickas. För att framgångsrikt läsa från flera öppna resultatuppsättningar måste du använda en MARS-aktiverad anslutning.

MARS är inaktiverat som standard, så du måste uttryckligen aktivera det genom att lägga till MultipleActiveResultSets=True i en anslutningssträng. Följande exempel visar hur man ansluter till en instans av SQL Server och anger att MARS är aktiverat:

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

MARS med In-Memory OLTP är i princip samma som MARS i resten av SQL-motorn. Följande listar skillnaderna vid användning av MARS i minnesoptimerade tabeller och nativt kompilerade lagrade procedurer.

MARS och minnesoptimerade tabeller

Följande är skillnaderna mellan diskbaserade och minnesoptimerade tabeller när man använder en MARS-aktiverad anslutning:

  • Två satser kan ändra data i samma målobjekt, men om båda försöker ändra samma post kommer en skriv-skriv-konflikt att orsaka att den nya operationen misslyckas. Men om båda operationerna ändrar olika poster kommer operationerna att lyckas.

  • Varje sats körs under SNAPSHOT-isolering så nya operationer kan inte se ändringar gjorda av de befintliga satserna. Även om de samtidiga satserna körs under samma transaktion skapar SQL-motorn batch-scoped transaktioner för varje sats som är isolerade från varandra. Dock är batch-scoped transaktioner fortfarande bundna tillsammans, så rollback av en batch-scoped transaktion påverkar andra i samma batch.

  • DDL-operationer är inte tillåtna i användartransaktioner så de kommer omedelbart att misslyckas.

MARS och nativt kompilerade lagrade procedurer

Nativt kompilerade lagrade procedurer kan köras i MARS-aktiverade anslutningar och kan endast köra en annan sats när en yield point påträffas. En yield point kräver ett SELECT-uttalande, vilket är det enda sättet inom en nativt kompilerad lagrad procedur som kan ge exekvering till ett annat sätt. Om en SELECT-sats inte finns i proceduren kommer den inte att ge, den kommer att köras till slut innan andra satser börjar.

MARS- och minnesinkopior av OLTP

Ändringar som görs av satser och atomblock som är sammanflätade isoleras från varandra. Till exempel, om ett uttalande eller atomblock gör vissa ändringar och sedan ger exekvering till ett annat uttalande, kommer det nya uttalandet inte att se ändringar som gjorts av det första uttalandet. Dessutom, när första satsen återupptar exekveringen, kommer den inte att se några ändringar gjorda av andra satser. Kontoutdrag kommer bara att visa ändringar som är klara och genomförda innan kontoutdraget startar.

En ny användartransaktion kan startas inom den aktuella användartransaktionen med BEGIN TRANSACTION-satsen – detta stöds endast i interop-läge så BEGIN TRANSACTION kan endast anropas från en T-SQL-sats, och inte från en native kompilerad lagrad procedur. Du kan skapa en sparpunkt i en transaktion med SAVE TRANSACTION eller ett API-anrop till transaktionen. Spara(save_point_name) för att rulla tillbaka till sparpunkten. Denna funktion aktiveras också endast från T-SQL-satser, och inte från inbyggda inbyggda lagrade procedurer.

MARS och kolumnstore-index

SQL Server (från och med 2016) stöder MARS med kolumnlagringsindex. SQL Server 2014 använder MARS för skrivskyddade anslutningar till tabeller med kolumnlagringsindex. SQL Server 2014 stöder dock inte MARS för samtidiga data manipulationsspråk (DML)-operationer på en tabell med kolumnlagreindex. När detta sker kommer SQL Server att avsluta anslutningarna och avbryta transaktionerna. SQL Server 2012 har skrivskyddade kolumnlagringsindex och MARS gäller inte för dem.

SQL Server Native Client OLE DB-provider

Den SQL Server Native Client OLE DB-leverantören stödjer MARS genom tillägget av egenskapen SSPROP_INIT_MARSCONNECTION datakällans initialisering, som implementeras i DBPROPSET_SQLSERVERDBINIT egenskapsuppsättningen. Dessutom har ett nytt nyckelord för anslutningssträngar, MarsConn, lagts till. Den accepterar sanna eller falska värden; False är standard.

Datakällsegenskapen DBPROP_MULTIPLECONNECTIONS som standard är VARIANT_TRUE. Detta innebär att leverantören kommer att skapa flera anslutningar för att stödja flera samtidiga kommando- och raduppsättningsobjekt. När MARS är aktiverat kan SQL Server Native Client stödja flera kommando- och raduppsättningsobjekt på en enda anslutning, så MULTIPLE_CONNECTIONS är inställd på VARIANT_FALSE som standard.

För mer information om förbättringar som gjorts i DBPROPSET_SQLSERVERDBINIT egenskapsuppsättning, se Initialization and Authorization Properties.

SQL Server Native Client OLE DB-leverantör exempel

I detta exempel skapas ett datakällobjekt med hjälp av SQL Server Native OLE DB-leverantör, och MARS aktiveras med egenskapsuppsättningen DBPROPSET_SQLSERVERDBINIT innan sessionsobjektet skapas.

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

SQL Server Native Client ODBC-drivrutinen stödjer MARS genom tillägg till funktionerna SQLSetConnectAttr och SQLGetConnectAttr. SQL_COPT_SS_MARS_ENABLED har lagts till för att acceptera antingen SQL_MARS_ENABLED_YES eller SQL_MARS_ENABLED_NO, där SQL_MARS_ENABLED_NO är standard. Dessutom har ett nytt reťazec pripojenia nyckelord, Mars_Connection, lagts till. Den accepterar "ja" eller "nej"-värden; "Nej" är standard.

SQL Server Native Client ODBC-drivrutinsexempel

I detta exempel används SQLSetConnectAttr-funktionen för att aktivera MARS innan SQLDriverConnect-funktionen anropas för att ansluta databasen. När anslutningen är gjord anropas två SQLExecDirect-funktioner för att skapa två separata resultatuppsättningar på samma anslutning.

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

Se även

inbyggda klientfunktioner i SQL Server
Användning av SQL Server standardresultatuppsättningar