Több aktív eredményhalmaznak (MARS) használata az SQL Server natív kliensben

A következőkre vonatkozik:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceAzure Synapse Analytics

Important

SQL Server Native Client (SNAC) nem kerül szállításra a következőkkel:

  • SQL Server 2022 (16.x) és újabb verziók
  • AZ SQL Server Management Studio 19- és újabb verziói

Az SQL Server natív ügyfele (SQLNCLI vagy SQLNCLI11) és az örökölt Microsoft OLE DB Provider for SQL Server (SQLOLEDB) nem ajánlott az új alkalmazásfejlesztéshez.

Új projektek esetén használja az alábbi illesztőprogramok egyikét:

Az SQL Server adatbázismotor (2012–2019) egyik összetevőjeként szállított SQLNCLI esetében tekintse meg az alábbi támogatási életciklus-kivételt.

Az SQL Server 2005 (9.x) bevezette a több aktív eredményhalmazt (MARS) támogatását azokban az alkalmazásokban, amelyek hozzáférnek az adatbázis motorhoz. Az SQL Server korábbi verzióiban az adatbázis-alkalmazások nem tudtak több aktív utasítást fenntartani egy kapcsolaton. Az SQL Server alapértelmezett eredményhalmazainak használatakor az alkalmazásnak egy tételből feldolgoznia vagy törölnie kellett az összes eredményhalmazt, mielőtt bármely másik kötetet végrehajthatott volna azon a kapcsolaton. Az SQL Server 2005 (9.x) új kapcsolati attribútumot vezetett be, amely lehetővé teszi, hogy az alkalmazások kapcsolatonként több függőben lévő kérést is tartalmazzanak, különösen egy kapcsolatonként több aktív alapértelmezett eredményhalmazt is legyen.

A MARS egyszerűsíti az alkalmazástervezést az alábbi új képességekkel:

  • Az alkalmazások több alapértelmezett eredményhalmazt is megnyithatnak, és ezek alapján össze tudnak olvasni.

  • Az alkalmazások más utasításokat is végrehajthatnak (például INSERT, , UPDATEDELETE, , és tárolt eljáráshívásokat), miközben az alapértelmezett eredményhalmazok nyitva vannak.

A MARS-t használó pályázatok az alábbi irányelveket hasznosnak találják:

  • Az alapértelmezett eredményhalmazokat rövid vagy rövid életű eredményhalmazokhoz kell használni, amelyeket egyetlen SQL utasítás generál (SELECT, DML kimenetelsel, RECEIVE, READ text stb.).

  • A szerverkurzorokat hosszabb életű vagy nagy eredményhalmazokhoz kell használni, amelyeket egyetlen SQL utasítás generál.

  • Eljárási kéréseknél mindig olvasd fel az eredmények végéig, függetlenül attól, hogy visszaadnak-e eredményt vagy sem, illetve azoknál a tételeknél, amelyek több eredményt adnak.

  • Ahol lehetséges, használj API-hívásokat a kapcsolati tulajdonságok megváltoztatására és a tranzakciók kezelésére a Transact-SQL utasítások helyett.

  • A MARS-ban a session keretében történő személyazonyítás tilos, amíg párhuzamosan zajlanak a sorozatok.

Note

Alapértelmezés szerint a MARS funkciót nem engedélyezi a meghajtó. Ahhoz, hogy a MARS SQL Server-hez SQL Server Native Client-hez csatlakozva használjuk, kifejezetten engedélyezned kell a MARS-t egy kapcsolati karakterlánc keretében. Azonban egyes alkalmazások alapértelmezés szerint engedélyezhetik a MARS-t, ha az alkalmazás észleli, hogy az illesztőprogram támogatja a MARS-t. Ezeknél az alkalmazásoknál szükség szerint letilthatod a MARS-t a kapcsolati karakterlánc-ben. További információért lásd az SQL Server Native Client OLE DB provider és az SQL Server Native Client ODBC driver szakaszokat a téma későbbi részében.

Az SQL Server Native Client nem korlátozza az aktív utasítások számát egy kapcsolaton.

A tipikus alkalmazások, amelyeknek nem kell egyszerre több többmondatos tételt vagy tárolt eljárást futtatniuk, profitálnak a MARS-ból anélkül, hogy érteniük kellene, hogyan valósítják meg a MARS-t. Azonban a bonyolultabb követelményeket igénylő alkalmazásoknak ezt figyelembe kell venniük.

A MARS lehetővé teszi több kérés interleave-alapú végrehajtását egyetlen kapcsolaton belül. Vagyis lehetővé teszi egy batch futtatását, és a végrehajtás során más kérések futtatását is lehetővé teszi. Fontos azonban megjegyezni, hogy a MARS interleaving szempontjából definiálható, nem pedig párhuzamos végrehajtás szempontjából.

A MARS infrastruktúra lehetővé teszi, hogy több tétel interleaved módon hajtson végre, bár a végrehajtás csak jól definiált pontokon lehet váltani. Ezen felül a legtöbb állításnak atomiszerűen kell futnia egy adagon belül. Azok a utasítások, amelyek visszaadják a sorokat a kliensnek, amelyeket néha hozási pontoknak is neveznek, engedélyezett, hogy a teljesítés befejezése előtt interleave-be kerüljön, miközben sorokat küldenek az ügyfélnek, például:

  • SELECT

  • FETCH

  • RECEIVE

Minden más utasításnak, amelyet egy tárolt eljárás vagy kötet részeként hajtanak végre, befejezésig kell futnia, mielőtt a végrehajtást más MARS kérésekre lehetne áthelyezni.

A batchesek végrehajtásának pontos módját számos tényező befolyásolja, és nehéz megjósolni, hogy pontosan milyen sorrendben hajtják végre több tételből származó parancsokat, amelyek hozampontokat tartalmaznak. Ügyelj arra, hogy elkerüld a nem kívánt mellékhatásokat, amelyek az ilyen összetett adagok interleave-es végrehajtása miatt járnak.

Kerüld el a problémákat azzal, hogy API-hívásokat használsz Transact-SQL utasítások helyett a kapcsolati állapot (SET, USE) és tranzakciók (BEGIN TRAN, COMMIT, ROLLBACK) kezelésére azzal, hogy ezeket a mondatokat nem illeszted be többmondatos kötetekbe, amelyek szintén hozampontokat tartalmaznak, és az ilyen tételek futtatását soriálissá tesszük, az összes eredmény lefogyasztásával vagy törlésével.

Note

Egy kötet vagy tárolt eljárás, amely kézi vagy implicit tranzakciót indít, amikor a MARS engedélyezett, a tranzakciót a batch kilépése előtt kell teljesítenie. Ha nem, az SQL Server visszavonja az összes tranzakció által végrehajtott változtatást, amikor a batch véget ér. Az ilyen tranzakciót az SQL Server csomag-alapú tranzakcióként kezeli. Ez egy új típusú tranzakció, amelyet az SQL Server 2005 (9.x) vezetett be, hogy lehetővé tegye a meglévő, jól viselkedő tárolt eljárások használatát, amikor a MARS be van kapcsolva. További információért a batch-scoped tranzakciókról lásd: Tranzakciós kimutatások (Transact-SQL).

Az ADO-ból készült MARS használatának példáját lásd: Az ADO használata SQL Server Native Client-szel.

In-Memory OLTP (memórián belüli OLTP)

A memórián belüli OLTP támogatja a MARS-t lekérdezések és natívan lefordított tárolt eljárások használatával. A MARS lehetővé teszi, hogy több lekérdezésből is kérjen adatokat anélkül, hogy minden eredményhalmazt teljesen le kellene kérni, mielőtt sorokat küldene egy új eredményhalmazból. Ahhoz, hogy több nyílt eredményhalmazból sikeresen olvass, MARS-kompatibilis kapcsolatot kell használni.

A MARS alapértelmezés szerint le van tiltva, így kifejezetten be kell kapcsolnod egy kapcsolati lánchoz hozzáadva MultipleActiveResultSets=True . Az alábbi példa bemutatja, hogyan lehet csatlakozni egy SQL Server példányhoz, és meghatározni, hogy a MARS engedélyezve legyen:

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

A MARS In-Memory OLTP-vel lényegében ugyanaz, mint a MARS az SQL motor többi részében. Az alábbiakban felsoroljuk a különbségeket a MARS használatakor memóriaoptimalizált táblákban és natívan fordított tárolt eljárásokban.

MARS és memóriaoptimalizált táblázatok

Az alábbiakban a lemezalapú és memóriaoptimalizált táblázatok közötti különbségek MARS-kompatibilis kapcsolat esetén:

  • Két állítás módosíthatja az adatokat ugyanabban a célobjektumban, de ha mindkettő megpróbálja módosítani ugyanazt a rekordot, egy írás-írás ütközés az új művelet sikertelenségét okozza. Azonban, ha mindkét művelet eltérő rekordokat módosít, a műveletek sikeresek lesznek.

  • Minden utasítás SNAPSHOT izoláció alatt fut, így az új műveletek nem láthatják a meglévő utasítások által végrehajtott változtatásokat. Még ha az egyidejű utasításokat ugyanazon tranzakció alatt is hajtják végre, az SQL motor minden utasításhoz egymástól elszigetelt batch-scoped tranzakciókat hoz létre. Azonban a batch-scoped tranzakciók továbbra is összekötöttek, így az egyik batch-scoped tranzakció visszafordítása befolyásolja a többi kötet ugyanabban a kötetben.

  • A DDL műveletek nem engedélyezettek a felhasználói tranzakciókban, így azonnal meghibásodnak.

MARS és natívan fordított tárolt eljárások

A natívan fordított tárolt eljárások MARS-engedélyezett kapcsolatokban futhatnak, és csak akkor engedhetnek végrehajtást egy másik utasításhoz, ha találkozik egy engedelmes ponttal. Egy yield point esetén SELECT utasítás szükséges, amely az egyetlen utasítás egy natívan lefordított tárolt eljárásban, amely képes egy másik utasítás futtatását eredményezni. Ha egy SELECT utasítás nincs jelen az eljárásban, akkor nem ad meg, és a befejezésig fut, mielőtt más utasítások kezdődnének.

MARS és memóriában lévő OLTP tranzakciók

Az állítások és atomblokkok által végrehajtott változtatások, amelyek egymástól elkülönítenek. Például, ha egy állítás vagy atomblokk változtatást hajt végre, majd egy másik utasítás végrehajtását eredményezi, az új utasítás nem látja az első állítás által végrehajtott változtatásokat. Ezen felül, amikor az első állítás folytatódik, nem lát más állítások által végrehajtott változtatásokat. A kijelentések csak azokat a változtatásokat látják, amelyeket a kijelentés kezdete előtt befejeznek és elköteleznek.

Egy új felhasználói tranzakciót indíthatunk el a jelenlegi felhasználói tranzakción belül a BEGIN TRANSACTION utasítással – ez csak interop módban támogatott, így a BEGIN TRANSACTION csak egy T-SQL utasításból hívható meg, nem pedig egy natívan lefordított tárolt eljárásból. Létrehozhatsz mentési pontot egy tranzakcióban SAVE TRANSACTION vagy egy API hívással a tranzakcióhoz. Mented(save_point_name) a mentési ponthoz való visszaguruláshoz. Ez a funkció csak T-SQL utasításokból engedélyezett, nem a natívan lefordított tárolt eljárásokból.

MARS és oszlopáruház indexek

Az SQL Server (2016-tól kezdve) támogatja a MARS-t columnstore indexekkel. SQL Server 2014 a MARS-t használja csak olvasható kapcsolatokhoz táblákhoz, amelyek oszloptároló indexkel rendelkeznek. Az SQL Server 2014 azonban nem támogatja a MARS-t egy oszloptároló indexű táblán végzett egyidejű adatkezelő nyelvi (DML) műveletekhez. Amikor ez megtörténik, az SQL Server megszünteti a kapcsolatokat és megszakítja a tranzakciókat. Az SQL Server 2012 csak olvasható oszlopos indexeket tartalmaz, és a MARS nem vonatkozik rájuk.

SQL Server natív ügyféloldali OLE DB-szolgáltató

Az SQL Server Native Client OLE DB szolgáltató támogatja a MARS-t a SSPROP_INIT_MARSCONNECTION adatforrás inicializációs tulajdonságának hozzáadásával, amely a DBPROPSET_SQLSERVERDBINIT tulajdonsághalmazban van megvalósítva. Ezen felül egy új kapcsolati lánc kulcsszó, a MarsConn is hozzáadódott. Elfogadja az igaz vagy hamis értékeket; A hamisság az alapértelmezett.

Az adatforrás tulajdonság DBPROP_MULTIPLECONNECTIONS alapértelmezés szerint VARIANT_TRUE. Ez azt jelenti, hogy a szolgáltató több kapcsolatot is létrehoz, hogy több párhuzamos parancs- és sorkészletobjektumot is támogatjon. Amikor a MARS engedélyezett, SQL Server Native Client több parancs- és sorkészlet objektumot is támogathat egyetlen kapcsolaton, így MULTIPLE_CONNECTIONS alapértelmezés szerint VARIANT_FALSE-ra van állítva.

További információért a DBPROPSET_SQLSERVERDBINIT tulajdonsághalmazban végrehajtott fejlesztésekről lásd: Initializációs és engedélyezési tulajdonságok.

SQL Server Native Client OLE DB Provider Példa

Ebben a példában egy adatforrás objektumot hoznak létre az SQL Server natív OLE DB szolgáltatóval, és a MARS a DBPROPSET_SQLSERVERDBINIT tulajdonsághalmazon keresztül van engedélyezve, mielőtt a session objektum létrejött.

#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 natív ügyfél ODBC-illesztőprogramja

Az SQL Server Native Client ODBC illezőprogramja támogatja a MARS-t az SQLSetConnectAttr és SQLGetConnectAttr funkciók bővítésével. SQL_COPT_SS_MARS_ENABLED hozzáadták, hogy SQL_MARS_ENABLED_YES vagy SQL_MARS_ENABLED_NO elfogadja, SQL_MARS_ENABLED_NO az alapértelmezett megoldás. Ezen felül egy új kapcsolati karakterlánc kulcsszó, a Mars_Connection is hozzáadódott. Elfogadja az "igen" vagy "nem" értékeket; A "nem" az alapértelmezett.

SQL Server Native Client ODBC driver példa

Ebben a példában az SQLSetConnectAttr függvényt használják a MARS engedélyezésére, mielőtt az SQLDriverConnect függvényt hívnánk az adatbázis összekapcsolásához. A kapcsolat létrejötte után két SQLExecDirect függvényt hívnak, hogy ugyanazon a kapcsolaton két különálló eredményhalmazt hozzanak létre.

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