Not
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Gäller för:SQL Server
Azure SQL Database
Azure SQL Managed Instance
Azure Synapse Analytics
Analysplattformssystem (PDW)
SQL-databas i Microsoft Fabric
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.
Anmärkning
Som standard är MARS-funktionaliteten inte aktiverad. För att använda MARS när du ansluter till SQL Server med OLE DB Driver för SQL Server måste du specifikt aktivera det inom en anslutningssträng. För mer information, se avsnitten OLE DB Driver för SQL Server, senare i detta ämne.
OLE DB Driver för SQL Server begränsar inte antalet aktiva satser på en anslutning.
Typiska applikationer som inte behöver ha mer än en enda multistatement-batch 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äldefinierade 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:a exekvering 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.
Anmärkning
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 Att använda ADO med OLE DB Driver för SQL Server.
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.
OLE DB-drivrutin för SQL Server
OLE DB-drivrutinen för SQL Server stödjer MARS genom tillägg av egenskapen SSPROP_INIT_MARSCONNECTION datakällsinitiering, som implementeras i egenskapen DBPROPSET_SQLSERVERDBINIT egenskap. 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 OLE DB Driver för SQL Server stödja flera kommando- och raduppsättningsobjekt på en och samma anslutning, så MULTIPLE_CONNECTIONS är inställt 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.
OLE DB-drivrutin för SQL Server-exempel
I detta exempel skapas ett datakällobjekt med OLE DB-drivrutinen för SQL Server, och MARS aktiveras med egenskapsuppsättningen DBPROPSET_SQLSERVERDBINIT innan sessionsobjektet skapas.
#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);