Поделиться через


Использование нескольких активных результирующих наборов (MARS)

SQL Server 2005 представила поддержку нескольких активных результирующих наборов (MARS) в приложениях, обращаюющихся к ядру СУБД. В более ранних версиях SQL Server приложения базы данных не могут поддерживать несколько активных инструкций в соединении. При использовании результирующих наборов SQL Server по умолчанию приложение пришлось обрабатывать или отменять все результирующие наборы из одного пакета, прежде чем выполнять любой другой пакет в этом подключении. В SQL Server 2005 появился новый атрибут подключения, который позволяет приложениям иметь несколько ожидающих запросов на подключение, и, в частности, иметь несколько активных результирующих наборов по умолчанию для каждого подключения.

MARS упрощает проектирование приложений со следующими новыми возможностями:

  • В приложениях может быть открыто несколько результирующих наборов по умолчанию и могут переключиться на чтение из них.

  • Приложения могут выполнять другие инструкции (например, INSERT, UPDATE, DELETE и хранимые процедуры) во время открытия результирующих наборов по умолчанию.

Приложения, использующие MARS, будут находить следующие рекомендации:

  • Наборы результатов по умолчанию следует использовать для коротких или коротких результирующих наборов, созданных одними операторами SQL (SELECT, DML с выходными данными, RECEIVE, READ TEXT и т. д.).

  • Курсоры сервера должны использоваться для длительного существования или больших результирующих наборов, созданных с помощью отдельных инструкций SQL.

  • Всегда читать до конца результатов для процедурных запросов независимо от того, возвращаются ли результаты или нет, и для пакетов, возвращающих несколько результатов.

  • По возможности используйте вызовы API для изменения свойств подключения и управления транзакциями в предпочтениях Transact-SQL инструкций.

  • В MARS запрещается олицетворение с областью действия сеанса при выполнении параллельных пакетов.

Замечание

По умолчанию функция MARS не включена. Чтобы использовать MARS при подключении к SQL Server с собственным клиентом SQL Server, необходимо специально включить его в строке подключения. Дополнительные сведения см. в разделах о поставщике OLE DB собственного клиента SQL Server и драйверах ODBC собственного клиента SQL Server.

Sql Server Native Client не ограничивает количество активных инструкций в соединении.

Типичные приложения, которые не должны иметь более одного пакета с несколькими статистическими данными или хранимой процедурой, выполняющимися одновременно, выиграют от MARS, не имея необходимости понимать, как реализуется MARS. Однако приложения с более сложными требованиями должны учитывать это.

MARS обеспечивает чередование нескольких запросов в одном соединении. То есть пакет может выполняться, и в рамках его выполнения он позволяет выполнять другие запросы. Однако обратите внимание, что MARS определяется с точки зрения взаимодействия, а не с точки зрения параллельного выполнения.

Инфраструктура MARS позволяет нескольким пакетам выполняться в чередованном режиме, хотя выполнение можно переключать только в определенных точках. Кроме того, большинство инструкций должны выполняться атомарны в пакете. Операторы, возвращающие строки клиенту, которые иногда называются точками доходности, могут пересекать выполнение до завершения, пока строки отправляются клиенту, например:

  • ВЫБЕРИТЕ

  • ПОЛУЧАТЬ

  • ПОЛУЧИТЕ

Любые другие инструкции, выполняемые в рамках хранимой процедуры или пакета, должны выполняться до завершения, прежде чем выполнение можно будет переключиться на другие запросы MARS.

Точное выполнение пакетных пакетов зависит от ряда факторов, и трудно предсказать точную последовательность, в которой будут выполняться команды из нескольких пакетов, содержащих точки доходности. Будьте осторожны, чтобы избежать нежелательных побочных эффектов из-за перемешанных выполнения таких сложных пакетов.

Избегайте проблем с помощью вызовов API, а не Transact-SQL инструкций для управления состоянием подключения (SET, USE) и транзакциями (BEGIN TRAN, COMMIT, ROLLBACK), не включая эти инструкции в пакетах с несколькими операторами, которые также содержат точки получения, и сериализируя выполнение таких пакетов путем использования или отмены всех результатов.

Замечание

Пакетная или хранимая процедура, которая запускает ручную или неявную транзакцию, когда MARS должна завершить транзакцию перед выходом пакета. Если это не так, SQL Server откатит все изменения, внесенные транзакцией после завершения пакета. Такая транзакция управляется SQL Server как транзакция с пакетной областью. Это новый тип транзакций, появившихся в SQL Server 2005, чтобы обеспечить правильное поведение хранимых процедур при включении MARS. Дополнительные сведения о транзакциях с пакетной областью см. в инструкциях транзакций (Transact-SQL).

Пример использования MARS из ADO см. в статье Using ADO with SQL Server Native Client.

Поставщик OLE DB для собственного клиента SQL Server

Поставщик OLE DB собственного клиента SQL Server поддерживает MARS через добавление свойства инициализации источника данных SSPROP_INIT_MARSCONNECTION, которое реализуется в наборе свойств DBPROPSET_SQLSERVERDBINIT. Кроме того, добавлено новое ключевое слово MarsConnстроки подключения. Он принимает true или false значения; false является значением по умолчанию.

Свойство источника данных DBPROP_MULTIPLECONNECTIONS по умолчанию VARIANT_TRUE. Это означает, что поставщик будет создавать несколько подключений для поддержки нескольких параллельных объектов команд и наборов строк. При включении MARS собственный клиент SQL Server может поддерживать несколько объектов команд и наборов строк в одном соединении, поэтому MULTIPLE_CONNECTIONS по умолчанию VARIANT_FALSE.

Дополнительные сведения о усовершенствованиях, внесенных в набор свойств DBPROPSET_SQLSERVERDBINIT, см. в разделе "Инициализация" и "Свойства авторизации".

Пример поставщика OLE DB для собственного клиента SQL Server

В этом примере объект источника данных создается с помощью поставщика OLE DB SQL Server Native, а MARS включен с помощью набора свойств DBPROPSET_SQLSERVERDBINIT перед созданием объекта сеанса.

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

Драйвер ODBC для собственного клиента SQL Server

Драйвер ODBC собственного клиента SQL Server поддерживает MARS через дополнения к функциям SQLSetConnectAttr и SQLGetConnectAttr . SQL_COPT_SS_MARS_ENABLED добавлен для принятия SQL_MARS_ENABLED_YES или SQL_MARS_ENABLED_NO, а SQL_MARS_ENABLED_NO — значение по умолчанию. Кроме того, добавлено новое ключевое слово Mars_Connectionстроки подключения. Он принимает значения "да" или "нет"; "нет" — это значение по умолчанию.

Пример драйвера ODBC для собственного клиента SQL Server

В этом примере функция SQLSetConnectAttr используется для включения MARS перед вызовом функции SQLDriverConnect для подключения к базе данных. После создания подключения вызываются две функции SQLExecDirect для создания двух отдельных результирующих наборов в одном соединении.

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

См. также

Компоненты собственного клиента SQL Server
Использование результирующих наборов по умолчанию SQL Server