Partilhar via


Usando MARS (vários conjuntos de resultados ativos)

O SQL Server 2005 introduziu o suporte a MARS (vários conjuntos de resultados ativos) dos aplicativos que acessem o Mecanismo de Banco de Dados. Em versões mais antigas do SQL Server, os aplicativos de banco de dados não podiam manter várias instruções ativas em uma conexão. Ao usar os conjuntos de resultados padrão do SQL Server, o aplicativo tinha que processar ou cancelar todos os conjuntos de resultados de um lote antes de executar outro lote nessa conexão. O SQL Server 2005 introduziu um novo atributo de conexão que permite que os aplicativos tenham mais que uma solicitação pendente por conexão e, especificamente, tenham mais que um conjunto de resultados padrão ativo por conexão.

O MARS simplifica o design de aplicativo com os seguintes novos recursos:

  • Os aplicativos podem ter vários conjuntos de resultados padrão abertos e intercalar a leitura a partir deles.

  • Os aplicativos podem executar outras instruções (por exemplo, INSERT, UPDATE, DELETE e chamadas de procedimento armazenado) enquanto os conjuntos de resultados padrão estiverem abertos.

Os aplicativos que usam o MARS considerarão as seguintes diretrizes vantajosas:

  • Os conjuntos de resultados padrão devem ser usados para conjuntos de curta duração ou resultados breves gerados por instruções exclusivas do SQL (SELECT, DML com OUTPUT, RECEIVE, READ TEXT etc).

  • Cursores de servidor devem ser usados para conjuntos de resultados grandes ou de duração mais longa gerados por instruções exclusivas do SQL.

  • Sempre leia os resultados até o fim para obter solicitações de procedimento – independentemente de os resultados serem retornados ou não – e de lotes que retornem vários resultados.

  • Sempre que possível, dê preferência ao uso de chamadas de API para alterar as propriedades de conexão e gerenciar transações em detrimento das instruções do Transact-SQL.

  • No MARS, a representação de escopo por sessão é proibida durante a execução dos lotes simultâneos.

ObservaçãoObservação

Por padrão, a funcionalidade de MARS não é habilitada. Para usar o MARS ao conectar-se ao SQL Server com o SQL Server Native Client, você deve habilitá-lo especificamente em uma cadeia de conexão. Para obter mais informações, consulte o provedor OLE DB do SQL Server Native Client e as seções sobre o driver ODBC do SQL Server Native Client, mais adiante neste tópico.

O SQL Server Native Client não limita o número de instruções ativas em uma conexão.

Aplicativos típicos que não precisam ter mais de um lote de várias instruções ou de um procedimento armazenado em execução ao mesmo tempo se beneficiarão do MARS mesmo que não saibam como é feita sua implementação. Porém, aplicativos com requisitos mais complexos devem levar isso em conta.

O MARS habilita a execução intercalada de várias solicitações em uma única conexão. Isto é, ele permite que um lote seja executado e, dentro de sua execução, permite a execução de outras solicitações. Observe, porém, que o MARS é definido em termos de intercalação, e não em termos de execução paralela.

A infra-estrutura do MARS permite que vários lotes sejam executados de uma maneira intercalada, embora a execução só possa ser alterada em pontos bem definidos. Além disso, a maioria das instruções deve ser executada atomicamente dentro de um lote. As instruções que retornam linhas para o cliente, que às vezes são chamadas de pontos de produção, têm permissão para intercalar execução antes da conclusão, enquanto as linhas estão sendo enviadas para o cliente, por exemplo:

  • SELECT

  • FETCH

  • RECEIVE

Qualquer outra instrução que seja executada como parte de um procedimento armazenado ou lote deve ser executada até a conclusão, antes que a execução possa ser alterada para outras solicitações do MARS.

A maneira exata que os lotes são intercalados na execução é influenciada por vários fatores e é difícil prever a seqüência exata em que os comandos de vários lotes que contêm pontos de produção será executada. Tenha cuidado para evitar efeitos colaterais indesejáveis devido a execução intercalada desses lotes complexos.

Evite problemas usando chamadas de API, em vez de instruções do Transact-SQL, para gerenciar o estado de conexão (SET, USE) e as transações (BEGIN TRAN, COMMIT, ROLLBACK), não incluindo essas instruções em lotes de várias instruções que contenham pontos de produção e serializando a execução de tais lotes consumindo ou cancelando todos os resultados.

ObservaçãoObservação

Um lote ou procedimento armazenado que inicie uma transação manual ou implícita quando o MARS está habilitado deve concluir a transação antes de ser encerrado. Se não fizer, o SQL Server acumulará todas as alterações feitas pela transação quando o lote for concluído. Essa transação é gerenciada pelo SQL Server como uma transação de escopo em lote. Este é um tipo novo de transação introduzido no SQL Server 2005 para habilitar procedimentos armazenados existentes com bom comportamento para uso quando o MARS for habilitado. Para obter mais informações sobre transações com escopo em lotes, consulte transações (Transact-SQL) e Controlando transações (Mecanismo de Banco de Dados).

Para obter um exemplo de como usar o MARS do ADO, consulte Usando o ADO com SQL Server Native Client.

Provedor OLE DB do SQL Server Native Client

O provedor OLE DB do SQL Server Native Client oferece suporte ao MARS por meio da adição da propriedade de inicialização da fonte de dados SSPROP_INIT_MARSCONNECTION, que é implementada no conjunto de propriedades DBPROPSET_SQLSERVERDBINIT. Além disso, uma nova palavra-chave de cadeia de conexão, MarsConn, foi adicionada. Ela aceita os valores true ou false; false é o padrão.

A propriedade da fonte de dados DBPROP_MULTIPLECONNECTIONS é padronizada como VARIANT_TRUE. Isto significa que o provedor gerará várias conexões para oferecer suporte a vários objetos simultâneos do conjunto de linhas e do comando. Quando MARS é habilitado, o SQL Server Native Client pode oferecer suporte a vários objetos do conjunto de linhas e do comando em uma única conexão, portanto MULTIPLE_CONNECTIONS é definido como VARIANT_FALSE por padrão.

Para obter mais informações sobre aprimoramentos realizados no conjunto de propriedades DBPROPSET_SQLSERVERDBINIT, consulte Propriedades de inicialização e autorização.

Exemplo de provedor OLE DB do SQL Server Native Client

Neste exemplo, um objeto da fonte de dados foi criado usando o provedor OLE DB do SQL Server Native e o MARS foi habilitado com o conjunto de propriedades DBPROPSET_SQLSERVERDBINIT antese da criação do objeto da sessão.

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

Driver ODBC do SQL Server Native Client

O driver ODBC do SQL Server Native Client oferece suporte a MARS por meio da adição das funções SQLSetConnectAttr e SQLGetConnectAttr. SQL_COPT_SS_MARS_ENABLED foi adicionada para aceitar SQL_MARS_ENABLED_YES ou SQL_MARS_ENABLED_NO, com SQL_MARS_ENABLED_NO sendo o padrão. Além disso, uma nova palavra-chave de cadeia de conexão, Mars_Connection, foi adicionada. Ela aceita valores “yes” ou “no”; “no” é o padrão.

Exemplo do driver ODBC do SQL Server Native Client

Neste exemplo, a função SQLSetConnectAttr é usada para habilitar o MARS antes de chamar a função SQLDriverConnect para conectar-se ao banco de dados. Quando a conexão é feita, duas funções SQLExecDirect são chamadas para criar dois conjuntos de resultados separados na mesma conexão.

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