Использование режима MARS

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

Режим MARS упрощает проектирование приложений за счет использования следующих функций:

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

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

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

  • Результирующие наборы по умолчанию следует использовать с имеющими небольшой период жизни или с короткими результирующими наборами, сформированными при помощи одной инструкции SQL (SELECT, DML-инструкций с OUTPUT, RECEIVE, READ TEXT и т. д.).

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

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

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

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

ПримечаниеПримечание

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

Собственный клиент SQL Server не ограничивает число активных инструкций для одного соединения.

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

Режим MARS дает возможность поочередно выполнять несколько запросов с использованием одного соединения. Иначе говоря, существует возможность выполнения пакета с одновременным выполнением других запросов. Впрочем, надо отметить, что режим MARS определяется в терминах чередования, а не в терминах параллельного выполнения.

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

  • SELECT

  • FETCH

  • RECEIVE

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

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

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

ПримечаниеПримечание

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

Пример использования режима MARS из кода, использующего ADO, см. в разделе Использование ADO с собственным клиентом SQL Server.

Поставщик 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, и режим 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. Оно принимает значения «yes» или «no»; по умолчанию принимается значение «no».

Пример драйвера 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);