Použití více aktivních sad výsledků (MARS) v nativním klientovi SQL Server

platí pro:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceAzure Synapse AnalyticsAnalytický platformní systém (PDW)

Důležité

SQL Server Native Client (SNAC) není dodáván s:

  • SQL Server 2022 (16.x) a novější verze
  • SQL Server Management Studio 19 a novější verze

Pro vývoj nových aplikací se nedoporučuje nativní klient SQL Serveru (SQLNCLI nebo SQLNCLI11) a starší zprostředkovatel Microsoft OLE DB pro SQL Server (SQLOLEDB).

Pro nové projekty použijte jeden z následujících ovladačů:

Informace o SQLNCLI, které se dodává jako součást databázového stroje SQL Serveru (verze 2012 až 2019), naleznete v tomto support lifecycle exception.

SQL Server 2005 (9.x) zavedl podporu více aktivních sad výsledků (MARS) v aplikacích přistupujících k databázovému enginu. V dřívějších verzích SQL Serveru nemohly databázové aplikace udržovat více aktivních příkazů na spojení. Při použití výchozích sad výsledků SQL Serveru musela aplikace zpracovat nebo zrušit všechny sady výsledků z jedné dávky, než mohla spustit jinou dávku na tomto připojení. SQL Server 2005 (9.x) zavedl nový atribut připojení, který umožňuje aplikacím mít více než jeden čekající požadavek na jedno připojení, a zejména více než jednu aktivní výchozí sadu výsledků na jedno připojení.

MARS zjednodušuje návrh aplikací o následující nové funkce:

  • Aplikace mohou mít otevřené více výchozích sad výsledků a mohou z nich prokládat čtení.

  • Aplikace mohou vykonávat jiné příkazy (například INSERT, UPDATE, DELETE, a uložené procedurální volání), zatímco výchozí výsledkové sady jsou otevřené.

Aplikace využívající MARS najdou přínosné následující pokyny:

  • Výchozí sady výsledků by měly být použity pro krátkodobé nebo krátkodobé sady výsledků generované jednotlivými SQL příkazy (SELECT, DML s OUTPUT, RECEIVE, READ TEXT a podobně).

  • Serverové kurzory by měly být používány pro delší životnost nebo velké sady výsledků generované jednotlivými SQL příkazy.

  • Vždy čtěte výsledky až do konce u procedurálních požadavků bez ohledu na to, zda výsledky vracejí nebo ne, a u šarží, které vracejí více výsledků.

  • Kde je to možné, používejte API volání ke změně vlastností spojení a spravujte transakce před Transact-SQL příkazy.

  • V MARS je simulace simulace v rámci session zakázána, dokud běží současné dávky.

Note

Ve výchozím nastavení není funkčnost MARS ovladačem povolena. Pro použití MARS při připojení k SQL Server s SQL Server Native Client musíte MARS konkrétně povolit v rámci připojovací řetězec. Některé aplikace však mohou MARS povolit ve výchozím nastavení, pokud aplikace zjistí, že ovladač podporuje MARS. Pro tyto aplikace můžete MARS v připojovací řetězec podle potřeby vypnout. Pro více informací viz sekce o SQL Server Native Client OLE DB provider a SQL Server Native Client ODBC ovladačích, později v tomto tématu.

SQL Server Native Client neomezuje počet aktivních příkazů na spojení.

Typické aplikace, které nemusí mít více než jednu vícepříkazovou dávku nebo uloženou proceduru vykonávanou současně, budou mít z MARS prospěch, aniž by musely rozumět implementaci MARS. Nicméně aplikace s náročnějšími požadavky musí toto zohlednit.

MARS umožňuje prokládání více požadavků v rámci jednoho spojení. To znamená, že umožňuje spustit dávku a během jejího vykonávání umožňuje vykonat i další požadavky. Je však třeba poznamenat, že MARS je definován z hlediska prokládání, nikoli paralelního provádění.

Infrastruktura MARS umožňuje provádění více dávek v prokládaném režimu, i když provádění lze přepínat pouze na dobře definovaných místech. Navíc většina tvrzení musí běžet atomicky v rámci dávky. Příkazy, které vracejí řádky klientovi, někdy označované jako yield points, mohou provádět prokládání před dokončením, zatímco řádky jsou klientu odesílány, například:

  • SELECT

  • FETCH

  • RECEIVE

Jakékoliv další příkazy, které jsou vykonávány jako součást uložené procedury nebo dávky, musí být dokončeny před tím, než lze převést na jiné MARS požadavky.

Přesný způsob, jakým batch prokládá prokládání, ovlivňuje řada faktorů a je obtížné předpovědět přesné pořadí, v jakém budou vykonány příkazy z více dávek obsahujících body výtěku. Buďte opatrní, abyste se vyhnuli nežádoucím vedlejším účinkům při prokládání takto složitých várek.

Vyhněte se problémům použitím API volání místo Transact-SQL příkazů pro správu stavu spojení (SET, USE) a transakcí (BEGIN TRAN, COMMIT, ROLLBACK) tím, že tyto příkazy nezahrnete do vícepříkazových dávek, které také obsahují výnosné body, a serializujte jejich provádění tím, že všechny výsledky spotřebováváte nebo rušíte.

Note

Dávková nebo uložená procedura, která zahájí manuální nebo implicitní transakci při zapnutí MARS, musí transakci dokončit před ukončením dávky. Pokud ne, SQL Server po dokončení batch stáhne všechny změny provedené transakcí zpět. Taková transakce je spravována SQL Serverem jako batch-scope transakce. Toto je nový typ transakce zavedený v SQL Server 2005 (9.x), který umožňuje použití existujících dobře fungujících uložených procedur při povolení MARS. Pro více informací o dávkově řízených transakcích viz Výpisy transakcí (Transact-SQL).

Pro příklad použití MARS z ADO viz Použití ADO s SQL Server Native Client.

Technologie zpracování OLTP v paměti (In-Memory OLTP)

OLTP v paměti podporuje MARS pomocí dotazů a nativně zkompilovaných uložených procedur. MARS umožňuje požadavek na data z více dotazů bez nutnosti úplně získat každou sadu výsledků před odesláním požadavku na načtení řádků z nové sady výsledků. Pro úspěšné čtení z více otevřených sad výsledků musíte použít připojení s podporou MARS.

MARS je ve výchozím nastavení zakázán, takže jej musíte explicitně povolit přidáním MultipleActiveResultSets=True do řetězce připojení. Následující příklad ukazuje, jak se připojit k instanci SQL Serveru a specifikovat, že je povolen MARS:

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

MARS s In-Memory OLTP je v podstatě stejný jako MARS v ostatních částech SQL enginu. Následuje seznam rozdílů při použití MARS v tabulkách optimalizovaných pro paměť a nativně kompilovaných uložených procedurách.

MARS a tabulky optimalizované pro paměť

Následují rozdíly mezi tabulkami založenými na disku a optimalizovanými tabulkami pro paměť při použití připojení s podporou MARS:

  • Dva příkazy mohou upravovat data ve stejném cílovém objektu, ale pokud se oba pokusí upravit stejný záznam, konflikt zápisu a zápisu způsobí selhání nové operace. Pokud však obě operace upraví různé záznamy, operace uspějí.

  • Každý příkaz běží v izolaci SNAPSHOT, takže nové operace nemohou vidět změny provedené stávajícími příkazy. I když jsou souběžné příkazy vykonány pod stejnou transakcí, SQL engine vytváří pro každý příkaz dávkově zaměřené transakce, které jsou od sebe odděleny. Nicméně transakce s dávkovým rozsahem jsou stále propojené, takže návrat jedné batch-scope transakce ovlivňuje i další v téže dávce.

  • DDL operace nejsou povoleny v uživatelských transakcích, takže okamžitě selžou.

MARS a nativně kompilované uložené procedury

Nativně kompilované uložené procedury mohou běžet v MARS podporovaných spojeních a mohou vést k vykonání jiného příkazu pouze při dosažení bodu výtěku. Yield point vyžaduje příkaz SELECT, což je jediný příkaz v nativně kompilované uložené procedurě, který může vést k vykonání jiného příkazu. Pokud v postupu není přítomen příkaz SELECT, který nevrátí, dokončí ho dříve, než začnou ostatní příkazy.

MARS a transakce OLTP v paměti

Změny vytvořené výroky a atomickými bloky, které jsou prokládány, jsou od sebe izolované. Například pokud jeden příkaz nebo atomický blok provede změny a pak vykoná jiný příkaz, nový příkaz neuvidí změny provedené prvním příkazem. Navíc, když první příkaz obnoví vykonání, neuvidí žádné změny vykonané jinými příkazy. Výpisy uvidí pouze změny, které jsou dokončeny a potvrzeny před začátkem prohlášení.

Novou uživatelskou transakci lze zahájit v rámci aktuální uživatelské transakce pomocí příkazu BEGIN TRANSACTION – to je podporováno pouze v interop režimu, takže BEGIN TRANSACTION lze volat pouze z T-SQL příkazu, nikoli z nativně kompilované uložené procedury. Uložený bod v transakci můžete vytvořit pomocí SAVE TRANSACTION nebo API call to transaction. Uložit(save_point_name) pro návrat k uloženému bodu. Tato funkce je také povolena pouze z T-SQL příkazů, nikoli z nativně zkompilovaných uložených procedur.

MARS a indexy columnstore

SQL Server (od roku 2016) podporuje MARS s indexy columnstore. SQL Server 2014 používá MARS pro připojení pouze pro čtení k tabulkám s indexem columnstore. SQL Server 2014 však nepodporuje MARS pro operace souběžného jazyka pro manipulaci s daty (DML) na tabulce s indexem columnstore. Když k tomu dojde, SQL Server ukončí připojení a transakce zruší. SQL Server 2012 má indexy columnstore pouze pro čtení a MARS se na ně nevztahuje.

Zprostředkovatel OLE DB nativního klienta SQL Serveru

Poskytovatel OLE DB SQL Server Native Client podporuje MARS přidáním inicializační vlastnosti SSPROP_INIT_MARSCONNECTION datového zdroje, která je implementována v sadě DBPROPSET_SQLSERVERDBINIT vlastností. Navíc bylo přidáno nové klíčové slovo pro spojovací řetězce, MarsConn. Přijímá pravdivé nebo nepravdivé hodnoty; False je výchozí.

Vlastnost zdroj dat DBPROP_MULTIPLECONNECTIONS výchozí VARIANT_TRUE. To znamená, že poskytovatel vytvoří více připojení, aby podpořil více současných příkazových a řádkových objektů. Když je MARS povolen, SQL Server nativní klient může podporovat více příkazových a řádkových objektů na jednom spojení, takže MULTIPLE_CONNECTIONS je ve výchozím nastavení nastaveno na VARIANT_FALSE.

Pro více informací o vylepšeních DBPROPSET_SQLSERVERDBINIT vlastnostní sadě viz Inicializace a autorizační vlastnosti.

Příklad poskytovatele SQL Server Native Client OLE DB

V tomto příkladu je objekt datového zdroje vytvořen pomocí poskytovatele SQL Server Native OLE DB a MARS je povolen pomocí sady DBPROPSET_SQLSERVERDBINIT před vytvořením objektu relace.

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

Ovladač ODBC nativního klienta SQL Serveru

Ovladač ODBC pro nativního klienta pro SQL Server podporuje MARS rozšířením funkcí SQLSetConnectAttr a SQLGetConnectAttr. SQL_COPT_SS_MARS_ENABLED bylo přidáno tak, aby přijímalo buď SQL_MARS_ENABLED_YES, nebo SQL_MARS_ENABLED_NO, přičemž výchozí SQL_MARS_ENABLED_NO je nastaveno. Navíc bylo přidáno nové klíčové slovo připojovací řetězec, Mars_Connection. Přijímá hodnoty "ano" nebo "ne"; "ne" je výchozí pravidlo.

Příklad ovladače pro nativní klient ODBC pro SQL Server

V tomto příkladu se funkce SQLSetConnectAttr používá k povolení MARS před vyvoláním funkce SQLDriverConnect pro připojení databáze. Jakmile je spojení navázáno, jsou volány dvě funkce SQLExecDirect, které vytvářejí dvě samostatné sady výsledků na stejném spojení.

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

Viz také

Funkce nativního klienta SQL Serveru
Použití výchozích sad výsledků SQL Server