Partilhar via


Usando vários conjuntos de resultados ativos (MARS)

Aplica-se a:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceAzure Synapse AnalyticsSistema de Plataforma de Análise (PDW)Base de dados SQL no Microsoft Fabric

Baixar driver OLE DB

O SQL Server 2005 (9.x) introduziu suporte para múltiplos conjuntos de resultados ativos (MARS) em aplicações que acedem ao Motor de Base de Dados. Em versões anteriores do SQL Server, as aplicações de base de dados não conseguiam manter múltiplas instruções ativas numa ligação. Ao usar conjuntos de resultados predefinidos do SQL Server, a aplicação tinha de processar ou cancelar todos os conjuntos de resultados de um lote antes de poder executar qualquer outro lote nessa ligação. O SQL Server 2005 (9.x) introduziu um novo atributo de ligação que permite às aplicações ter mais do que um pedido pendente por ligação e, em particular, ter mais do que um conjunto de resultados ativo por defeito por ligação.

O MARS simplifica o design de aplicações com as seguintes novas capacidades:

  • As aplicações podem ter múltiplos conjuntos de resultados por defeito abertos e podem intercalar a leitura a partir deles.

  • As aplicações podem executar outras instruções (por exemplo, INSERT, UPDATE, DELETE e chamadas de procedimentos armazenados) enquanto os conjuntos de resultados predefinidos estão abertos.

As candidaturas que utilizem MARS considerarão benéficas as seguintes diretrizes:

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

  • Os cursores do servidor devem ser usados para conjuntos de resultados de maior duração ou grandes gerados por instruções SQL únicas.

  • Leia sempre até ao fim dos resultados para pedidos procedurais, independentemente de estes devolverem resultados ou não, e para lotes que devolvam múltiplos resultados.

  • Sempre que possível, utilize chamadas de API para alterar propriedades de ligação e gerir transações em vez de instruções Transact-SQL.

  • No MARS, a imitação com âmbito de sessão é proibida enquanto lotes simultâneos estão a decorrer.

Observação

Por defeito, a funcionalidade MARS não está ativada. Para usar o MARS ao ligar-se ao SQL Server com o OLE DB Driver for SQL Server, tem de o ativar especificamente dentro de uma cadeia de ligação. Para mais informações, consulte as secções do Driver OLE DB para SQL Server, mais adiante neste tópico.

O OLE DB Driver para SQL Server não limita o número de instruções ativas numa ligação.

Aplicações típicas que não precisam de mais do que um único batch multistatement ou procedimento armazenado a executar simultaneamente beneficiarão do MARS sem terem de compreender como o MARS é implementado. No entanto, aplicações com requisitos mais complexos precisam de ter isso em conta.

O MARS permite a execução intercalada de múltiplos pedidos numa única ligação. Ou seja, permite que um lote seja executado e, dentro da sua execução, permite que outros pedidos sejam executados. Note-se, no entanto, que o MARS é definido em termos de intercalação, não em termos de execução paralela.

A infraestrutura MARS permite que múltiplos lotes sejam executados de forma intercalada, embora a execução só possa ser comutada em pontos bem definidos. Além disso, a maioria das instruções tem de ser executada atómicamente dentro de um lote. Instruções que retornam linhas ao cliente, por vezes chamadas de yield points, podem intercalar a execução antes da conclusão enquanto as linhas estão a ser enviadas ao cliente, por exemplo:

  • SELECT

  • FETCH

  • RECEIVE

Quaisquer outras instruções que sejam executadas como parte de um procedimento armazenado ou lote devem ser executadas até à conclusão antes de a execução poder ser transferida para outros pedidos MARS.

A forma exata como os lotes entrelaçam a execução é influenciada por vários fatores, sendo difícil prever a sequência exata em que os comandos de múltiplos lotes que contêm pontos de yield serão executados. Tenha cuidado para evitar efeitos secundários indesejados devido à execução intercalada de lotes tão complexos.

Evite problemas usando chamadas de API em vez de Transact-SQL instruções para gerir o estado da ligação (SET, USE) e transações (BEGIN TRAN, COMMIT, ROLLBACK), não incluindo estas instruções em lotes de múltiplas instruções que também contenham pontos de yield, e serializando a execução desses lotes ao consumir ou cancelar todos os resultados.

Observação

Um procedimento por lote ou armazenado que inicia uma transação manual ou implícita quando o MARS está ativado deve concluir a transação antes que o batch saia. Se não o fizer, o SQL Server reverte todas as alterações feitas pela transação quando o lote termina. Tal transação é gerida pelo SQL Server como uma transação em lote. Este é um novo tipo de transação introduzido no SQL Server 2005 (9.x) para permitir a utilização de procedimentos armazenados existentes e bem comportados quando o MARS está ativado. Para mais informações sobre transações por lote, consulte Extratos de Transação (Transact-SQL).

Para um exemplo de utilização de MARS a partir de ADO, veja Utilização de ADO com OLE DB Driver para SQL Server.

OLTP em Memória

O OLTP em memória suporta MARS usando consultas e procedimentos armazenados compilados nativamente. O MARS permite pedir dados de múltiplas consultas sem necessidade de recuperar completamente cada conjunto de resultados antes de enviar um pedido para buscar linhas de um novo conjunto de resultados. Para ler com sucesso de múltiplos conjuntos de resultados abertos, deve usar uma ligação habilitada pelo MARS.

O MARS está desativado por defeito, por isso tens de o ativar explicitamente adicionando MultipleActiveResultSets=True a uma cadeia de ligação. O exemplo seguinte demonstra como se ligar a uma instância de SQL Server e especificar que o MARS está ativado:

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

O MARS com In-Memory OLTP é essencialmente o mesmo que o MARS no resto do motor SQL. Segue-se as diferenças ao utilizar MARS em tabelas otimizadas para memória e em procedimentos armazenados compilados nativamente.

MARS e tabelas otimizadas para memória

Seguem-se as diferenças entre tabelas baseadas em disco e otimizadas para memória ao utilizar uma ligação habilitada pelo MARS:

  • Duas instruções podem modificar dados no mesmo objeto alvo, mas se ambas tentarem modificar o mesmo registo, um conflito de escrita-escrita fará com que a nova operação falhe. No entanto, se ambas as operações modificarem registos diferentes, as operações terão sucesso.

  • Cada instrução é executada sob isolamento SNAPSHOT, pelo que as novas operações não conseguem ver alterações feitas pelas instruções existentes. Mesmo que as instruções concorrentes sejam executadas sob a mesma transação, o motor SQL cria transações em lote para cada instrução que estão isoladas umas das outras. No entanto, as transações com âmbito de lote continuam ligadas entre si, pelo que o rollback de uma transação com âmbito de lote afeta as outras do mesmo lote.

  • As operações DDL não são permitidas nas transações dos utilizadores, por isso falham imediatamente.

MARS e procedimentos armazenados compilados nativamente

Procedimentos armazenados compilados nativamente podem correr em ligações habilitadas por MARS e só podem gerar execução para outra instrução quando é encontrado um ponto de yield. Um yield point requer uma instrução SELECT, que é a única instrução dentro de um procedimento armazenado compilado nativamente que pode dar origem à execução de outra instrução. Se uma instrução SELECT não estiver presente no procedimento que não irá gerar, será executada até à conclusão antes de começarem outras instruções.

Transações MARS e OLTP em memória

As alterações feitas por afirmações e blocos atómicos intercalados estão isolados uns dos outros. Por exemplo, se uma instrução ou bloco atómico fizer algumas alterações e depois ceder a execução a outra instrução, a nova instrução não verá alterações feitas pela primeira sentença. Além disso, quando a primeira instrução retoma a execução, não verá quaisquer alterações feitas por outras instruções. As declarações só verão alterações concluídas e confirmadas antes do início da declaração.

Uma nova transação de utilizador pode ser iniciada dentro da transação de utilizador atual usando a instrução BEGIN TRANSACTION – isto é suportado apenas em modo interop, pelo que a BEGIN TRANSACTION só pode ser chamada a partir de uma instrução T-SQL, e não dentro de um procedimento armazenado compilado nativamente. Pode criar um ponto de gravação numa transação usando o SAVE TRANSACTION ou uma API call to transaction. Guarda (save_point_name) para voltar ao ponto de gravação. Esta funcionalidade é também ativada apenas a partir de instruções T-SQL, e não dentro de procedimentos armazenados compilados nativamente.

Índices MARS e columnstore

O SQL Server (a partir de 2016) suporta MARS com índices de column store. O SQL Server 2014 utiliza o MARS para ligações apenas de leitura a tabelas com um índice columnstore. No entanto, o SQL Server 2014 não suporta o MARS para operações concorrentes de linguagem de manipulação de dados (DML) numa tabela com um índice columnstore. Quando isto acontece, o SQL Server termina as ligações e aborta as transações. O SQL Server 2012 tem índices de column store apenas leitura e o MARS não se aplica a eles.

Driver OLE DB para SQL Server

O Driver OLE DB para SQL Server suporta o MARS através da adição da propriedade de inicialização de SSPROP_INIT_MARSCONNECTION fonte de dados, que é implementada no conjunto de propriedades DBPROPSET_SQLSERVERDBINIT. Além disso, foi adicionada uma nova palavra-chave de string de ligação, MarsConn. Aceita valores verdadeiros ou falsos ; False é o padrão.

A propriedade da fonte de dados DBPROP_MULTIPLECONNECTIONS por defeito para VARIANT_TRUE. Isto significa que o fornecedor irá gerar múltiplas ligações para suportar múltiplos objetos de comando e conjunto de linhas concorrentes. Quando o MARS está ativado, o OLE DB Driver para SQL Server pode suportar múltiplos objetos de comando e conjunto de linhas numa única ligação, pelo que MULTIPLE_CONNECTIONS está definido para VARIANT_FALSE por defeito.

Para mais informações sobre melhorias feitas ao conjunto de propriedades DBPROPSET_SQLSERVERDBINIT, consulte Propriedades de Inicialização e Autorização.

Exemplo do Driver OLE DB para SQL Server

Neste exemplo, um objeto fonte de dados é criado usando o Driver OLE DB para SQL Server, e o MARS é ativado usando o conjunto de propriedades DBPROPSET_SQLSERVERDBINIT antes de o objeto de sessão ser criado.

#include <msoledbsql.h>  
  
IDBInitialize *pIDBInitialize = NULL;  
IDBCreateSession *pIDBCreateSession = NULL;  
IDBProperties *pIDBProperties = NULL;  
  
// Create the data source object.  
hr = CoCreateInstance(CLSID_MSOLEDBSQL, 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);  

Ver também

Driver OLE DB para Funcionalidades do SQL Server