Pontos de Dados

Uma visão geral do Banco de Dados de Documentos do Microsoft Azure

Julie Lerman

Baixar o código de exemplo(VB)

Julie LermanEm novembro de 2011, escrevi uma coluna chamada "Que diabos são os bancos de dados de documentos?" (msdn.microsoft.com/magazine/hh547103) em que abordei alguns dos bancos de dados de documentos mais conhecidos: O MongoDB, CouchDB e o RavenDB. Todos esses três bancos de dados que não são SQL ainda são fortes. Naquele momento, a Microsoft não tinha um banco de dados de documentos no mercado, embora ela tivesse o Armazenamento de Tabela do Microsoft Azure, um banco de dados que não é SQL, com base nos pares de chave-valor. No entanto, em agosto de 2014, O Banco de Dados de Documentos do Microsoft Azure foi anunciado, que, como o nome sugere, é um serviço de banco de dados de documentos não SQL disponível no Azure.

Nesta coluna, fornecerei uma visão geral do Banco de Dados de Documentos do Azure que espero que desertará a sua curiosidade o suficiente para investigar ainda mais por conta própria. O serviço está disponível no Azure e já estava em uso mesmo antes de sua elevação em 8 de abril de uma visualização para um recurso normalmente disponível. Por exemplo, há uma história de cliente excelente sobre uma empresa chamada SGS que implementou um Banco de Dados de Documentos como parte de uma solução em bit.ly/1GMnBd9. Um dos desenvolvedores desse projeto me enviou uma tweet sobre isso e disse que o cliente está muito satisfeito com ele até o momento.

O que é um banco de dados de documentos?

Minha coluna anterior era voltada para responder a essa pergunta, mas vou discutir rapidamente aqui e recomendo que você leia sobre isso nessa outra coluna. Um banco de dados de documentos armazena dados como documentos, principalmente como documentos do JSON individuais. (O MongoDB tem um pequeno detalhe porque ele transforma seus documentos JSON em um formato binário chamado BSON.) Esse armazenamento fornece um desempenho muito mais rápido ao trabalhar com grandes quantidades de dados porque ele não precisa saltar sobre todo o banco de dados para reunir dados relacionados. Os dados relacionados podem ser combinados em um único documento JSON. Outro recurso principal de um banco de dados de documentos e outros bancos de dados não SQL é que eles não têm esquema. Ao contrário de um banco de dados relacional cujas tabelas precisam de esquemas predefinidos para armazenar e recuperar dados, um banco de dados de documentos permite que cada documento defina seu próprio esquema. Dessa forma, o banco de dados é composto por conjuntos de documentos. A Figura 1 mostra um exemplo simples da provável aparência de um documento individual do JSON. Observe que ele especifica um nome de propriedade junto com o valor e que ele contém dados relacionados.

Figura 1 Um documento JSON simples

{
  "RecipeName": "Insane Ganache",
  "DerivedFrom": "Café Pasqual’s Cookbook",
  "Comments":"Insanely rich. Estimate min 20 servings",
  "Ingredients":[
    {
      "Name":"Semi-Sweet Chocolate",
      "Amount":"1.5 lbs",
      "Note":"Use a bar, not bits. Ghiradelli FTW"
    },
    {
      "Name":"Heavy cream",
      "Amount":"2 cups"
    },
    {
      "Name":"Unsalted butter",
      "Amount":"2 tbs"
    }
],
  "Directions": "Combine chocolate, cream and butter in the top ..."
}

Todos esses dados não estão apenas em formato JSON e são autodescritivos, mas eles contém dados relacionados (ingredientes). Outro recurso comum a alguns desses bancos de dados de documentos é que eles são acessíveis por meio de chamadas HTTP. Você verá mais sobre isso posteriormente e, novamente, a coluna anterior entra em detalhes sobre esses e outros recursos que são comuns a esses bancos de dados.

Estrutura do Banco de Dados de Documentos do Azure

A Figura 1 mostra a aparência de um documento típico armazenado em um banco de dados de documentos. No entanto, o Banco de Dados de Documentos do Azure é composto por mais do que apenas esses documentos. Os documentos são considerados um recurso no Banco de Dados de Documentos do Azure e podem ser agrupados em conjuntos, que também são recursos em Banco de Dados de Documentos. Você pode criar, atualizar, excluir e consultar coleções usando chamadas HTTP, assim como com documentos. Na verdade, o Banco de Dados de Documentos é inteiramente composto de diferentes tipos de recursos. As coleções são agrupadas em um único banco de dados Banco de Dados de Documentos. Você pode ter vários bancos de dados em uma conta de Banco de Dados de Documentos e é possível ter várias contas.

Todos esses recursos são cidadãos de primeira classe em todo o ambiente. Além disso, há um outro conjunto de recursos que acompanham seus documentos. Esses são denominados de forma que é familiar aos usuários de banco de dados relacionais: Procedimentos armazenados, Funções definidas por usuário (UDFs), Índices e Disparadores.

Um último recurso relacionado aos documentos é um anexo, que é qualquer tipo de binário que é anexado ao documento JSON. O binário do anexo reside no armazenamento de Blob do Azure, mas os metadados são armazenados no Banco de Dados de Documentos, garantindo que você pode consultar por anexos em uma variedade de propriedades.

Além disso, o Banco de Dados de Documentos tem recursos internos de segurança e, dentro do escopo, Usuários e Permissões também são recursos que você pode interagir com o uso da mesma maneira como você faria com documentos.

Interagindo com Banco de Dados de Documentos

Há inúmeras maneiras de trabalhar com recursos no Banco de Dados de Documentos do Azure, incluindo: SQL, API REST e várias APIs clientes, incluindo a API .NET, que permite usar o LINQ para consultar o banco de dados. Você pode aprender muito mais sobre os detalhes da consulta em bit.ly/1aLm4bC.

O Portal do Azure é onde você pode criar e gerenciar uma conta de Banco de Dados de Documentos. (Consulte a documentação em bit.ly/1Cq8zE7.) Você pode também gerenciar seu Banco de Dados de Documentos no portal, bem como usar Gerenciador de documentos e Gerenciador de consultas para visualizar e consultar seus documentos. No Gerenciador de consulta, você pode usar a sintaxe SQL, como foi feito para a consulta simples na Figura 2.

Usando a sintaxe SQL para consultar documentos no Gerenciador de consulta de Portal do Azure
Figura 2 Usando a sintaxe SQL para consultar documentos no Gerenciador de consulta de Portal do Azure

Você também pode usar o SQL em seus aplicativos. Por exemplo, aqui está um código de "Criar um Aplicativo da Web Node.js usando Banco de Dados de Documentos" (bit.ly/1E7j5Wg), onde a consulta é expressa na sintaxe SQL:

getOrCreateDatabase: function (client, databaseId, callback) {
  var querySpec = {
    query: 'SELECT * FROM root r WHERE r.id=@id',
    parameters: [{
      name: '@id',
      value: databaseId
    }]
  };

No início dos Banco de Dados de Documentos, você pode encontrar essa sintaxe SQL limitada, mas tenha em mente que você pode complementar a SQL existente com UDFs. Por exemplo, você pode escrever sua própria função CONTAINS para criar predicados que avaliam as cadeias de caracteres, como CONTAINS (r.name, "Chocolate").

Como muitos outros recursos do Azure, o Banco de Dados de Documentos do Azure tem uma API REST nativa e pode ser consultado e atualizado usando HTTP. Cada recurso tem um URI exclusivo.  Aqui está um exemplo de uma solicitação HTTP para uma determinada permissão do Banco de Dados de Documentos:

GET https://contosomarketing.documents.azure.com/dbs/ruJjAA==/users/ruJjAFjqQAA=/permissions/ruJjAFjqQABUp3QAAAAAAA== HTTP/1.1
x-ms-date: Sun, 17 Aug 2014 03:02:32 GMT
authorization: type%3dmaster%26ver%3d1.0%26sig%3dGfrwRDuhd18ZmKCJHW4OCeNt5Av065QYFJxLaW8qLmg%3d
x-ms-version: 2014-08-21
Accept: application/json
Host: contosomarketing.documents.azure.com

Vá para bit.ly/1NUIUd9 para obter detalhes sobre como trabalhar com a API REST diretamente. Mas trabalhar com qualquer API REST pode ser muito complicado. Existem inúmeras APIs de cliente já disponíveis para interagir com o Banco de Dados de Documentos do Azure: .NET, Node.js, JavaScript, Java e Python. Baixe os SDKs e leia a documentação em bit.ly/1Cq9iVJ.

Os desenvolvedores de .NET apreciarão a biblioteca .NET que permite a consulta usando LINQ. Embora o fornecimento de suporte ao método LINQ aumentará definitivamente ao longo do tempo, as expressões de LINQ com fornecimento de suporte no momento são: Queryable.Where, Queryable.Select e Queryable.SelectMany.

Antes de realizar qualquer interação com um Banco de Dados de Documentos, é necessário especificar uma conta, o banco de dados e a coleção na qual você deseja trabalhar. A seguir, por exemplo, define um Microsoft.Azure.Documents.ClientDocument usando a API .NET:

string endpoint = ConfigurationManager.AppSettings["endpoint"];
string authKey = ConfigurationManager.AppSettings["authKey"];
Uri endpointUri = new Uri(endpoint);
client = new DocumentClient(endpointUri, authKey);

Este código de exemplo vem de um passo a passo do ASP.NET MVC e Banco de Dados de Documentos seguido na página de documentação do Azure (bit.ly/1HS6OEe). O passo a passo é bastante completo, começando com as etapas para criar uma conta de Banco de Dados de Documentos no Portal do Azure. Recomendo muito ele ou, como alternativa, uma das instruções do passo a passo que demonstram o Banco de Dados de Documentos com outras linguagens, como o artigo do Node.js que mencionei anteriormente. O aplicativo de exemplo possui um único tipo, uma classe de Item, mostrado na Figura 3.

Figura 3 A classe do Item

public class Item
  {
    [JsonProperty(PropertyName = "id")]
    public string Id { get; set; }
    [JsonProperty(PropertyName = "name")]
    public string Name { get; set; }
    [JsonProperty(PropertyName = "descrip")]
    public string Description { get; set; }
    [JsonProperty(PropertyName = "isComplete")]
    public bool Completed { get; set; }
  }

Observe que cada propriedade da classe item especifica um JsonProperty PropertyName. Isso não é obrigatório, mas permite ao cliente .NET mapear entre os dados JSON armazenados e meu tipo de Item e permite nomear propriedades da minha classe da forma que eu quero, independentemente de como eles são nomeados no banco de dados. Usando o cliente definido, você pode expressar uma consulta LINQ que retorna uma instância de um Microsoft.Azure.Documents.Database dado um Id de banco de dados conhecido:

var db = Client.CreateDatabaseQuery()
               .Where(d => d.Id == myDatabaseId)
               .AsEnumerable()
               .FirstOrDefault();

A partir daí, você pode definir uma coleção no banco de dados e finalmente consultar a coleção com uma expressão LINQ semelhante a seguinte, que retorna um único documento JSON:

return Client.CreateDocumentQuery(Collection.DocumentsLink)
             .Where(d => d.Id == id)
             .AsEnumerable()
             .FirstOrDefault();

Os diversos objetos na API .NET também permitem operações de inserir, atualizar e excluir documentos com os métodos CreateDocument, UpdateDocumentAsync e DeleteDocumentAsync (CUD), que encapsulam as chamadas HTTP na API REST. Como as consultas, há métodos CUD relevantes para outros tipos de recursos, como procedimentos armazenados e anexos.

Um novo lado do limite

Um dos aspectos mais interessantes do Banco de Dados de Documentos que o diferencia dos outros bancos de dados de documentos é que ele permite que você ajuste a consistência. No meu artigo anterior sobre bancos de dados de documentos falamos sobre o Teorema de Extremidade, o qual diz que das garantias fornecidas de tolerância de "consistency, availability e partition" (consistência, disponibilidade e partição - CAP) em um sistema distribuído, apenas podemos obter duas ou três. Os bancos de dados relacionais garantem consistência ao custo da disponibilidade (por exemplo, aguardando a conclusão de uma transação). Bancos de dados não SQL, por outro lado, são mais tolerantes a consistência eventual, onde os dados podem não ser 100% atuais, para favorecer a disponibilidade.

O Banco de Dados de Documentos do Azure fornece uma nova maneira de resolver o Teorema de Extremidade, permitindo que você ajuste o nível de consistência, oferecendo a oportunidade de se beneficiar também de disponibilidade e tolerância a partição ao mesmo tempo. Você pode escolher entre quatro níveis de consistência — forte, sem obsolescência limitada, sessão e eventual — que podem ser definidos por operação, não apenas no banco de dados. Em vez de toda ou nenhuma consistência, você pode ajustar o nível de consistência para atender às suas necessidades ao longo de suas soluções. Leia mais sobre isso na documentação da página do Banco de Dados de Documentos do Azure em bit.ly/1Cq9p3v.

JavaScript do lado do servidor

Muitos de vocês provavelmente estão familiarizados com os procedimentos armazenados e UDFs em bancos de dados relacionais e, ao contrário de outros bancos de dados de documentos, o Banco de Dados de Documentos do Azure inclui esses conceitos, embora eles estão escritos em JavaScript. O JavaScript nativamente pode interagir com JSON, por isso é extremamente eficiente para interagir com os documentos JSON e outros recursos. Nenhuma transformação ou tradução ou mapeamento é necessário. Outro benefício de ter JavaScript do lado do servidor na forma de procedimentos armazenados e disparadores UDF é que você obtém transações atômicas em vários documentos — tudo no escopo da transação será revertido se um processo falhar. Definir procedimentos armazenados e UDFs é bastante diferente do que pode ser usado para um banco de dados relacional, como o SQL Server. O portal ainda não oferece esse recurso.  Em vez disso, você deve definir o código do lado do servidor em seu código do lado do cliente. É recomendável examinar a seção de Script do lado do servidor de Exemplos de código .NET do Banco de Dados de Documentos do Azure em bit.ly/1FiNK4y.

Agora, mostrarei como criar e armazenar um procedimento armazenado e como executá-lo. A Figura 4 mostra um exemplo simples que usa o código de API do .NET para inserir um procedimento armazenado em um Banco de Dados de Documentos.

Figura 4 Inserindo um procedimento armazenado em um Banco de Dados de Documentos

public static async Task<StoredProcedure> InsertStoredProcedure() {
  var sproc = new StoredProcedure
              {
                Id = "Hello",
                Body = @"
                  function() {
                    var context = getContext();
                    var response = context.getResponse();
                    response.setBody('Stored Procedure says: Hello World');
                  };"
              };
  sproc = await Client.CreateStoredProcedureAsync(setup.Collection.SelfLink, sproc);
  return sproc;
}

Encapsulei toda a lógica em um único método para manter a simplicidade. Meu objeto StoredProcedure consiste em uma ID e um corpo. O corpo é o JavaScript do lado do servidor. Talvez você prefira criar arquivos de JavaScript para cada procedimento e ler seu conteúdo ao criar o objeto StoredProcedure. O código presume que o StoredProcedure ainda não existe no banco de dados. No exemplo de download, você verá que chamo um método personalizado que consulta o banco de dados para garantir que o procedimento não existe mais antes de inseri-lo. Finalmente, uso SetupDocDb<T>.Client property (que fornece a instância DocumentClient) para criar o procedimento armazenado, semelhante à consulta para um documento anterior.

Agora que o procedimento armazenado existe no banco de dados, posso usá-lo. Tive um pouco mais de dificuldade para entender porque estou acostumado ao funcionamento do SQL Server, e isso é diferente. Mesmo que eu saiba que a Id do procedimento é "Hello", com a API atual que não é suficiente para identificá-lo ao chamar ExecuteStoredProcedureAsync. Cada recurso tem um SelfLink criado pelo Banco de Dados de Documentos. Um SelfLink é uma chave imutável que dá suporte aos recursos REST do Banco de Dados de Documentos. Isso garante que cada recurso tenha um endereço HTTP imutável. É necessário que SelfLink informe ao banco de dados qual procedimento armazenado executar. Isso significa que preciso primeiro consultar o banco de dados para localizar o procedimento armazenado usando a conhecida Id ("Hello") para que eu possa encontrar seu valor SelfLink. Esse fluxo de trabalho está causando atrito para desenvolvedores e a equipe do Banco de Dados de Documentos está mudando como ele funciona para eliminar a necessidade de SelfLinks. Essa alteração pode até mesmo estar sendo feita no momento que este artigo passou à imprensa. Mas, por enquanto, farei a consulta ao procedimento como eu faria para qualquer recurso do Banco de Dados de Documentos: Usarei o método CreateStoredProcedureQuery. Em seguida, com o SelfLink, posso executar o procedimento e obter seus resultados:

public static async Task<string> GetHello() {
  StoredProcedure sproc = Client.CreateStoredProcedureQuery(Collection.SelfLink)
    .Where(s => s.Id == "Hello")
    .AsEnumerable()
    .FirstOrDefault();
  var response =
    (await Client.ExecuteStoredProcedureAsync<dynamic>(sproc.SelfLink)).Response;
  return response.ToString();
}

Criar UDFs é semelhante. Defina a UDF como JavaScript em um objeto UserDefinedFunction e insirá-o no Banco de Dados de Documentos. Quando ele existir no banco de dados, você pode usar essa função em suas consultas. Inicialmente, isso era possível somente usando a sintaxe SQL como um parâmetro do método CreateDocumentQuery, embora fornecimento do suporte ao LINQ tenha sido adicionado antes do lançamento oficial do Banco de Dados de Documentos no início de abril de 2015. Aqui está um exemplo de uma consulta SQL usando uma UDF personalizada:

select r.name,udf.HelloUDF() AS descrip from root r where r.isComplete=false

A UDF simplesmente emite algum texto para que ele não use nenhum parâmetro.

Observe que estou usando os nomes de JsonProperty na consulta porque ela será processada no servidor em relação aos dados JSON. Com as consultas LINQ usei os nomes das propriedades do tipo de Item em seu lugar.

Você encontrará uma consulta semelhante que está sendo usada no download de exemplo, embora minha UDF é chamada HelloUDF.

Desempenho e escalabilidade

Há muitos fatores que entram em ação quando falamos sobre desempenho e escalabilidade. Até mesmo o design de seus modelos de dados e partições pode afetar essas facetas críticas de qualquer repositório de dados. É altamente recomendável ler as excelentes diretrizes sobre modelagem de dados no Banco de Dados de Documentos em bit.ly/1Chrjqa. Esse artigo aborda os prós e contras de design de elementos gráficos e relações e como eles afetam o desempenho e a escalabilidade do Banco de Dados de Documentos. O autor, Ryan CrawCour, que é o gerente de programa sênior da equipe do Banco de Dados de Documentos, explica quais padrões beneficiam o desempenho de leitura e os que beneficiam o desempenho de gravação. Na verdade, descobri que as diretrizes são úteis para design de modelo em geral, não apenas para Banco de Dados de Documentos do Azure.

Como você optar por dividir seu banco de dados também deve ser determinado por sua necessidades de leitura e gravação. O artigo sobre o particionamento de dados no Banco de Dados de Documentos em bit.ly/1y5T4FG fornece mais orientação sobre o uso de coleções de Banco de Dados de Documentos para definir partições e como definir coleções dependendo de como você precisará acessar os dados.

Como outro benefício do particionamento, você pode criar (ou remover) mais coleções ou bancos de dados, conforme necessário. O Banco de Dados de Documentos dimensiona elasticamente. Ou seja, ele automaticamente compreenderá o conjunto completo de recursos.

Os índices são outro fator importante que afetam o desempenho e o Banco de Dados de Documentos permite configurar políticas de indexação em conjuntos. Sem a indexação, você só poderá usar os SelfLinks e Ids de recursos para executar a consulta, como fiz anteriormente. A política de indexação padrão tenta encontrar um equilíbrio entre o desempenho da consulta e a eficiência do armazenamento, mas você pode substituí-la para obter o equilíbrio desejado. Os índices também são consistentes, o que significa pesquisas que aproveitam a indexação para terem acesso imediato aos novos dados. Leia mais detalhes sobre indexação na bit.ly/1GMplDm.

Não é grátis, mas é econômico

O gerenciamento de desempenho e escalabilidade afeta mais do que a acessibilidade de seus dados, ele também afeta o custo de fornecer esses dados. Como parte de suas ofertas do Azure, o Banco de Dados de Documentos vêm com um preço. Há três faixas de preço determinadas pela escolha de um dos três níveis de desempenho. Como a Microsoft está constantemente ajustando o custo de seus serviços, é mais seguro apontar diretamente para a página de detalhes de preços do Banco de Dados de Documentos (bit.ly/1IKUUMo). Como qualquer banco de dados não SQL, o Banco de Dados de Documentos é destinado a fornecer armazenamento de dados para enormes quantidades de dados e, portanto, pode ser muito mais econômico do que trabalhar com dados relacionais nos cenários relevantes.


Julie Lerman é MVP da Microsoft, mentora e consultora do .NET, que reside nas colinas de Vermont. Você pode encontrá-la em apresentações sobre acesso de dados ou sobre outros tópicos .NET em grupos de usuários e conferências em todo o mundo. Ela publica no blog thedatafarm.com/blog e é a autora do “Programming Entity Framework” (2010), bem como de Code First edition (2011) e DbContext edition (2012), todos da O’Reilly Media. Siga Julie no Twitter em twitter.com/julielerman e confira seus cursos da Pluralsight em juliel.me/PS-Videos.

Agradecemos ao seguinte especialista técnico da Microsoft pela revisão deste artigo: Ryan CrawCour
Ryan CrawCour é um veterano com 20 anos de banco de dados que começou escrevendo seu primeiro procedimento armazenado para o SQL Server 4.2 há muitos anos. Vários cursores, junções e procedimentos armazenados mais tarde, ele começou explorando o incrível mundo livre das soluções não SQL. Ryan está trabalhando agora com a equipe de produto do Banco de Dados de Documentos em Redmond como Gerente de programa ajudando a formar o futuro desse novo banco de dados com um serviço não SQL