Você está na página 1de 25

III Escola Regional de Informática do Piauí. Livro Anais - Artigos e Minicursos, v. 1, n. 1, p. 254-279, jun, 2017.

www.eripi.com.br/2017 - ISBN: 978-85-7669-395-6

Capítulo

1
Ajuste de Performance em Bancos de Dados NoSQL

Arlino Henrique Magalhães de Araújo, José Maria da Silva Monteiro Filho,


Angelo Roncalli Alencar Brayner

Abstract

In the last decade, there has been an exponential growth in the amount of data to be
stored. Thus, many applications have had the need to store and process large amounts
of data, often in real time, in order to make the request of viable information. However,
traditional storage systems has not kept pace. An alternative to this problem has been
NoSQL databases due to features like high availability, scalability, and flexibility to ma-
nage large amounts of data. However, with these advantages of NoSQL, there is a need for
monitoring and setting of these databases to ensure desired performance in applications.
This short course aims to a presentation of main concepts related to NoSQL technology
and strategies to optimize its performance.

Resumo

Na última década, houve um crescimento exponencial na quantidade de dados a serem


armazenados. Assim, muitas aplicações tem tido a necessidade de armazenar e processar
grandes quantidades de dados, muitas vezes em tempo real, a fim de tornar a recuperação
da informação viável. Entretanto, os sistemas de armazenamento tradicionais não tem
acompanhado essa demanda. Um alternativa para esse problema tem sido a utilização
de bancos de dados NoSQL devido a características como alta disponibilidade, escala-
bilidade e flexibilidade para gerenciar grandes quantidades de dados. Contudo, aliado
a essas vantagens de NoSQL, há a necessidade de monitoramento e configuração desses
bancos de dados para assegurar o desempenho desejado nas aplicações. Esse mini-curso
visa uma apresentação dos principais conceitos relacionados da tecnologia NoSQL e de
estratégias para otimizar seu desempenho.

1.1. Introdução e motivação


Por muitos anos o modelo relacional foi a principal opção para resolver problemas, tanto
grandes como pequenos, de armazenamento de dados. Contudo, muitas aplicações atuais
tem necessitado de um massivo fluxo de dados que os SGBDRs (Sistemas de Gerencia-
mento de Banco de Dados Relacionais) não conseguem gerenciar. Os bancos de dados
NoSQL tem sido uma alternativa amplamente reconhecida para aplicações com grande
volume de dados que necessitam de desempenho escalável, alta disponibilidade e resili-
ência.
Além disso, os bancos de dados NoSQL fornecem estruturas de dados intuitivas
e flexíveis; escalamento horizontalmente; baixo custo operacional; e, dependendo do fa-
bricante, algumas funcionalidades especiais, tais como: índices específicos, capacidade
de consulta de dados geoespaciais, replicação automática de dados, funcionalidades para
sincronização, dentre outros.

1.1.1. Big Data


Atualmente a facilidade de geração e aquisição de dados gerados digitalmente; através
máquinas fotográficas digitais, computadores, smartphones, GPS, redes de sensores, apa-
relhos domésticos, veículos e etc.; podem chegar à ordem de gigabytes. Este volume
de informações geradas e sua diversidade muitas vezes inviabilizam os processamentos
e análises pelas ferramentas tradicionais. Informações com esta característica recebem o
nome de Big Data.
As características do contexto Big Data podem ser resumidas em quatro propri-
edades: (1) dados na ordem de dezenas ou centenas de terabytes (podendo chegar a or-
dem de petabytes), (2) poder de crescimento elástico, (3) distribuição do processamento
dos dados; e (4) tipos de dados variados, complexos e/ou semiestruturados. A enorme
quantidade de dados a ser analisada, na ordem de terabytes ou petabytes, requer alto
poder computacional de armazenamento e processamento de dados. A elasticidade diz
repeito a quantidade de dados poder variar de poucos megabytes a vários terabytes (e
vice-versa) em um espaço de tempo relativamente curto, fazendo com que a estrutura de
software/hardware tenha que se adaptar sob demanda. Devido a grande quantidade de
dados, a distribuição do processamento e armazenado dos dados, de forma transparente, é
um requisito essencial. Por fim, em Big Data, há a adoção de modelos mais apropriados,
flexíveis e eficientes para o armazenamento de tipos de dados variados e semiestruturados.
Como consequência, novas demandas Big Data estão surgindo, como a demanda
por análise de grande volume de dados em tempo real (data analytics), o aumento do
detalhamento das informações, bem como plataformas escaláveis e eficientes de baixo
custo. A análise de dados no contexto de Big Data normalmente envolve grandes quanti-
dades de dados de baixo valor (isto é, informação original "bruta") que são transformados
para dados de maior valor (por exemplo, valores agregados/sumarizados). Por exemplo,
a análise de dados da ordem de petabytes de cunho científicos (como, dados genômicos,
física ambiental e simulações numéricas) tem se tornado muito comum.
Para ilustrar melhor a aplicação de Big Data, seguem alguns exemplos de utiliza-
ção dessa tecnologia:

• Oferecer filmes: a Netflix utiliza Big Data para indicar filmes a seus usuários de
acordo com suas preferências.
• Evitar suicídios: O projeto Durkheim acompanha redes sociais para detectar pala-
vras e frases que caracterizem o autor como um potencial suicida.
• Encontrar namorados: Alguns sites e aplicativos de encontro já usam Big Data
para identificar entre seus usuários cadastrados quais são aqueles que tem a maior
chance de formar casais com potencial de dar certo.
• Eleger candidatos: Nas eleições de 2012, Barack Obama recolheu por 18 meses
dados sobre seus eleitores na internet. Isso permitiu uma melhor compreensão dos
interesses e preocupações do eleitorado e, provavelmente, o ajudou a ser reeleito
presidente dos EUA.
• Espionar pessoas: Em 2013, Edward Snowden revelou a existência na NSA do
X-Keyscore, que captura todo o conteúdo que trafega na conexão interceptada para,
depois, analisá-lo e extrair os dados desejados. Só em 2012, agências federais dos
EUA gastaram 5 bilhões de dólares com pesquisas em Big Data.
• Ganhar a Copa!: A Seleção Alemã usou uma solução em Big Data chamada
Match Insights. O aplicativo processava todo o volume de informações gerado em
uma partida ou mesmo na preparação.

1.1.2. MapReduce
Proposto pela Google, o modelo MapReduce provê uma maneira de programação para-
lela para processamento de grandes quantidades de dados em diversos formatos. Esse
modelo pode utilizar clusters (conjunto de computadores) de baixo custo que, aliados a
um controle de falhas, são capazes de proporcionar bom desempenho e robustez. Um dos
objetivos do modelo foi abstrair do usuário a complexidade dos gerenciamentos como,
por exemplo, paralelização, tolerância a falhas, distribuição dos dados entre os nós e o
balanceamento do processamento.
Um programa que utiliza o modelo de programação MapReduce é formado por
duas operações básicas: map e reduce. A operação de map subdivide os dados de um
fluxo de trabalho em partes menores para que possam ser processados paralelamente entre
os vários nós de um cluster. A operação de reduce recombina os dados processados na
solução final. Em geral a operação de map é usada para encontrar algo e a operação de
reduce é usada para fazer a sumarização do resultado. Nesse mini-curso vamos detalhar
as implementações MapReduce Hadoop e Spark.

1.1.3. Consistência
As propriedades de transações ACID (Atômica, Consistente, Isolada e Durável) tornam o
trabalho do desenvolvedor de aplicações muito mais simples. Mas apesar de muito desejá-
veis, essas propriedades criam dificuldades ao se distribuir o banco de dados. Geralmente,
distribuir os dados é necessário quando a capacidade de um banco de dados cresce além
de um nó. Os bancos de dados NoSQL possuem maior facilidade para distribuição dos
dados de forma elástica.
O teorema CAP (Consistency, Availability e Partition tolerance) afirma que exis-
tem três propriedades que são desejáveis em banco de dados distribuído de grande porte:
consistência, disponibilidade e tolerância a partições. Entretanto, somente duas dessas
três propriedades podem ser garantidas. Como não é possível alcançar todos os três ob-
jetivos simultaneamente, uma das propriedades tem que ser desprezada. A seguir, é feita
uma breve discussão sobre as propriedades CAP:

• Consistência (Consistency): se um registro for modificado, qualquer busca futura


a esse registro deve retornar o valor atualizado.

• Disponibilidade (Availability): o banco deve estar disponível, mesmo que um ou


mais servidores estejam inacessíveis.

• Tolerância a particionamento (Partition-tolerance): os servidores podem perder


a comunicação entre eles por tempo indeterminado.

Uma arquitetura comum para aumentar a disponibilidade é a master slave, na qual


há um servidor principal (master) e um ou mais servidores secundários (slaves) com có-
pia dos dados do principal. Nessa abordagem, as escritas são feitas apenas no master que
automaticamente replica os dados para o slave. As leituras podem ser feitas no master
ou no slave. Caso o servidor master caia, um dos slaves pode assumir como master. A
Figura 1.1 ilustra a arquitetura master slave. Mesmo com essa arquitetura, há decisões
que devem ser tomadas quanto as propriedade CAP que devem ser priorizadas. Algu-
mas abordagens podem ser utilizadas, como: cAP ou AP (disponibilidade e tolerância a
particionamento priorizadas em detrimento a consistência) e; CaP ou CP (consistência e
tolerância a particionamento priorizadas em detrimento a disponibilidade).

Figura 1.1. Arquitetura master slave em um cluster.

Na abordagem cAP, durante uma falha de comunicação (tolerância a particiona-


mento), o sistema continua respondendo (disponibilidade), mas com dados desatualizados
(consistência). Por exemplo, se o banco principal confirmar a escrita antes de propagá-la
para o secundário, uma consulta no secundário pode resultar em dados diferentes (incon-
sistentes) do principal. Se houver uma falha no servidor principal, antes dele propagar as
atualizações, os dados podem ser perdidos. Se a comunicação entre o servidor principal
e o secundário for perdida, as escritas ainda são possíveis no principal e a leitura ainda é
possível em ambos, mesmo que desatualizas no secundário.
Na abordagem CaP, durante uma falha na comunicação (tolerância a particiona-
mento), não há dados desatualizados (consistência), mas há perdas de oportunidades de
escrita (disponibilidade). Usando o conceito de transação distribuída, o dado é conside-
rado salvo apenas após todas as réplicas confirmarem a escrita. Dessa forma, somente
após a escrita, qualquer leitra será consistente. Entretanto, como há a necessidade de con-
firmação de todos os nós secundários, a escrita torna-se mais lenta e, consequentemente,
as leituras tem que esperar a confirmação da escrita. Além disso, caso ocorra uma falha
de comunicação entre os servidores, a escrita não poderá ser confirmada e, consequente-
mente, a escrita não será efetivada.
Alguns bancos de dados NoSQL utilizam a arquitetura masterless, na qual qual-
quer servidor pode receber requisições de leitura e escrita. Assim, mesmo com falha na
rede ou em um servidor, o cluter consegue manter leitras e escritas disponíveis. Como
consequência, essa abordagem compromete a consistência. Além disso, podem haver
conflitos de escritas entre os servidores quando eles estiverem sincronizando os dados no
cluster. Para resolver essas divergências, existem algumas estratégias implementadas nos
bancos para decidir qual escrita é a correta.
A partir do teorema CAP, os produtos NoSQL utilizam o paradigma BASE (Basi-
cally Available, Soft-state, Eventually consistency) para o controle de consistência, o que,
consequentemente, traz uma sensível diminuição no custo computacional para a garan-
tia de consistência dos dados em relação a SGBD tradicionais. Nesse paradigma, (BA)
em casos de falha, o banco deve continuar respondendo mesmo que retorne dados in-
consistentes ou desatualizados; (Ss) é possível que duas consultas iguais retornem dados
diferentes e; (Ec) a consistência não é garantida, mas toda atualização é propagada.

1.1.4. Computação em Nuvem


Computação em Nuvem (Cloud Computing) é uma tendência recente da tecnologia que
como um modelo de entrega e de acesso a dados no qual os recursos virtualizados e di-
namicamente escalados são entregues como um serviço através da internet. Esse modelo
introduz um modelo de pagamento dos recursos utilizados conforme o uso (sob demanda),
eliminando os pesados investimentos iniciais da implantação de um sistema. Na nuvem
os recursos são monitorados possibilitando a tarifação de acordo com o uso, de forma
semelhante a maneira como os serviços de telefonia e energia, por exemplo. Com isso, os
usuários podem alugar capacidade de computação e armazenamento, em vez de investir
na aquisição e instalação de equipamentos.
O modelo de Computação em Nuvem possui cinco características básicas essen-
ciais:

1. Self-service sob demanda: os recursos computacionais podem ser adquiridos pelo


usuário conforme a sua necessidade sem precisar de interação humana.

2. Amplo acesso à rede: recursos computacionais são disponibilizados na rede em


tempo real e acessados por meio de mecanismos padronizados.

3. Pool de recursos: os recursos computacionais do fornecedor são agrupados de


forma a atender múltiplos usuários (modelo multi-tenant) de acordo com a demanda
de cada usuário.

4. Elasticidade: os recursos computacionais são provisionados de forma rápida e elás-


tica, em certos casos automaticamente, dando a impressão de serem ilimitados.

5. Serviços mensuráveis: para garantir a transparência tanto para o fornecedor como


para o usuário, a utilização dos recursos deve ser monitorada, controlada e reportada
de forma quantitativa e qualitativa.

Ambientes de computação em nuvem têm sido utilizados para o gerenciamento


de dados em forma de Big Data e precisam ter a capacidade de suportar alta carga de
atualizações e processos de análises de dados. Os data centers são uma das bases da
computação em nuvem, pois uma grande estrutura como serviço escalável e dinâmica é
fornecida para vários clientes.

1.2. Ferramentas NoSQL


Esta seção trata das principais ferramentas relacionados a tecnologia NoSQL, como pro-
dutos, linguagens de acesso, manipulação e processamento dos dados. Além disso, é dada
uma visão geral e prática dos tipos de bancos de dados NoSQL: chave-valor, colunar, ori-
entado a documentos e orientado a grafos.

1.2.1. Hadoop
O Hadoop é uma implementação de código aberto do paradigma de programação MapRe-
duce. Os programas que são desenvolvidos nesse paradigma realizam o processamento
paralelo de conjuntos de dados. A razão para a escalabilidade desse paradigma é a na-
tureza distribuída do funcionamento da solução: uma grande tarefa é dividida em várias
tarefas pequenas que são então executadas em paralelo em máquinas diferentes para, em
seguida, serem combinadas para chegar à solução de uma tarefa maior inicial. O fra-
mework do Hadoop é formado por dois componentes principais: o armazenamento de
arquivo chamado HDFS (Hadoop Distributed File System) manipula o armazenamento
de dados entre todas as máquinas na qual o cluster do Hadoop está sendo executado e; a
estrutura de programação MapReduce manipula a parte do processamento do framework.

1.2.2. Spark
O Spark é uma ferramenta Big Data que tem o objetivo de processar grandes conjuntos de
dados de forma paralela e distribuída. Essa ferramenta estende o modelo de programação
MapReduce popularizado pelo Hadoop facilitando bastante o desenvolvimento de aplica-
ções de processamento de dados. Esse framework implementa o conceito dos RDDs (Re-
silient Distributed Datasets), permitindo o reuso de dados distribuídos em uma variedade
de aplicações. Além do modelo de programação estendido, o Spark também apresenta
uma performance muito superior ao Hadoop, chegando em alguns casos a apresentar um
desempenho quase 100x maior. Entretanto, Spark não faz armazenamento distribuído e
precisa ser integrado a algum, que poder ser, inclusive, o HDFS.

1.2.3. Bancos de dados NoSQL


Os bancos de dados NoSQL não adotam o modelo relacional e são mais flexíveis quanto
as propriedades ACID. Por isso, muitas tarefas realizadas pelos SGBDRs ficam a cargo
do programador. Contudo, a estrutura simplificada desses bancos torna-os adequados aos
requisitos de alta escalabilidade para o gerenciamento de grandes quantidades de dados
(estruturados, não-estruturados ou semiestruturados) e a alta disponibilidades dos mes-
mos. Seguem algumas características dos bancos de dados NoSQL:
• Escalabilidade horizontal: A medida que um volume de dados cresce, aumenta
a necessidade de escalabilidade e melhoria de desempenho. Aumentar o poder de
processamento e armazenamento das máquinas (escalabilidade vertical) torna-se
inviável devido ao aumento de concorrência dos processo aos dados em uma mesma
máquina. Além disso, o hardware tem limites de escalabilidade. Uma alternativa
é aumentar o número de máquina disponíveis (escalabilidade horizontal) e dividir
uma tarefa entre vários processos distribuídos entre as máquinas.

• Ausência de esquema ou esquema flexível: Devido a essa característica, há uma


fácil aplicação da escalabilidade e também um aumento na disponibilidade. Mas
também devido a isso, não há garantia da integridade dos dados.

• Suporte a replicação: Os banco de dados NoSQL permitem a replicação de uma


forma nativa o que provê uma escalabilidade maior e também uma diminuição do
tempo gasto para a recuperação de informações.

• Consistência eventual: essa característica implica que nem sempre os dados esta-
rão consistentes entre os nós no cluster, mas uma hora estarão, até que as atualiza-
ções sejam propagadas.

Nas sub-seções a seguir serão discutidos os principais tipos de bancos de dados


NoSQL: colunar, chave-valor, orientado a documentos e orientado a grafos. Os principais
conceitos e comandos de cada banco serão abordados de maneira breve, visto o pouco
espaço disponível no paper. Fica a cargo do leitor buscar tutorias de instalação, configu-
ração e conexão com cada um dos bancos de dados apresentados nesse mini-curso.

1.2.3.1. Bando de dados NoSQL orientado a documentos

O modelo orientado a documentos armazena coleções de documentos e em cada docu-


mento há um conjunto de campos (chaves) e o valor deste campo. Esse tipo de banco
não possuem esquemas (shemeless) e modificações na estrutura dos documentos não cau-
sam impactos que podem ocorrer em SGBDRs, mas a custo de riscos de inconsistências.
Eexemplos de bancos orientados a documentos são: MongoDB, CouchDB, BigCouch,
RavenDB, Clusterpoint Server, ThruDB, TerraStore, RaptorDB, JasDB, SisoDB, SDB,
SchemaFreeDB, djondb. Nessa seção serão mostrados exemplos práticos de como mode-
lar, consultar e recuperar dados no banco de dados orientado a documentos MongoDB.
O MongoDB é um projeto open source com distribuição gratuita para Linux, Mac
e Windows. Embora seja escrito em C++, seu ambiente iterativo e suas buscas são escritas
em JavaScript. Os dados de um documento em uma coleção (equivalente a linha de uma
tabela) são armazenados no formato BSON (semelhante a JSON). Resumidamente, um
BSON pode ser definido entre os caracteres chaves {} e, dentro deles, são definidos grupos
de chaves e seus respectivos valores. Os valores também podem ser listas de chaves-
valores. A Figura 1.2 ilustra um registro no formato BSON.
A Figura 1.3 mostra como inserir um documento utilizando o comando insert.
Esse documento representa dados de um álbum de músicas inserido na coleção albuns.
Adicionalmente, podem ser inseridos outros álbuns com diferentes informações, tais como:
data de lançamento, estúdio de gravação, nome do artista que desenhou a capa, número
de singles, quantidade de semanas que ficou em primeiro lugar na billboard e etc.. Entre-
tanto, alguns álbuns podem não possuir todas essas informações. Por exemplo, a grande
maioria dos álbuns não possui nenhum single e, consequentemente, esse dado seria ine-
xistente em muitos documentos. Em um banco de dados relacional, onde existe o conceito
de tabela, todos os registros de uma tabela devem seguir um mesmo esquema. Os bancos
NoSQL baseados em documentos permitem que os documentos, de uma mesma coleção,
tenham esquemas diferentes.

{
first: ’Arlino’
lastename: ’Magalhães’
email: [’home’: ’arlinoh@gmail.com’,
’work’: ’arlino@ufpi.edu.br’],
phone: [’home’: ’+810001000’],
adress: []
}

Figura 1.2. Um documento no formato BSON de uma base de dados em MongoDB.

db.albuns.insert ({
"nome_album": "Legião Urbana",
"duracao": 3286
)}

Figura 1.3. Inserção de documento no MongoDB.

O comando find pode ser utilizado para buscar documentos no MongoDB. A Fi-
gura 1.4 mostra como fazer uma busca na coleção albuns utilizando um filtro no formato
BSON que busca pelo álbum de nome Legião Urbana. Sem o filtro (BSON vazio) o co-
mando find buscaria por todos os documentos da coleção. Para fins ilustrativos, a SQL
da Figura 1.5 de um SGBDR é equivalente ao comando MongoDB da Figura 1.4. Assim
como nos SGBDRs, nos quais uma tabela deve possuir uma chave primária, no MongoDB
todas as coleções possuem um campo chamado _id, que também funciona como chave
primária, mas é gerenciado pelo própria banco. Assim, o resultado obtido pelo comando
find da Figura 1.4 deve retornar o _id de cada documento, além dos outros campos.

db.albuns.find ({"nome_album": "Legião Urbana"})

Figura 1.4. Seleção de um documento no MongoDB.


SELECT * FROM albuns WHERE nome_album = ’Legião Urbana’

Figura 1.5. Seleção em um SGBD relacional.

Os relacionamentos no MongoDB são realizado referenciando o _id de um objeto


de outra coleção (semelhantemente a uma chave estrangeira). Por exemplo, o documento
da Figura 1.6 representa um gênero musical cujo _id pode ser referenciado em um docu-
mento de um álbum, como é mostrado no documento da Figura 1.7. Nesse documento,
o campo id_genero recebe o mesmo _id (ObjectId("54d1562cf7bb967d7b976d07")) do
documento da Figura 1.6. Assim, para mostrar todos os álbuns com seus respectivos gê-
neros musicais, basta apenas listar todos os documentos da coleção de álbuns e para cada
campo id_genero de um álbum, buscar o documento de _id correspondente na coleção de
gêneros. O código da Figura 1.8 mostra como fazer essa busca. Nesse código, a primeira
linha busca todos os álbuns armazenando-os na variável albuns. Na segunda linha há a
função forEach que recebe como argumento outra função, na qual é feita uma nova busca
na coleção generos pelo documento correspondente ao id_genero de cada álbum.

{
"_id": ObjectId("54d1562cf7bb967d7b976d07"),
"nome_genero": "MPB00
}

Figura 1.6. Documento de uma coleção de gêneros musicais.

{
"_id": ObjectId("63c828b5342dda43e93bee1e"),
"nome_album": "Legião Urbana
"duracao": 3286
"id_genero": ObjectId("54d1562cf7bb967d7b976d07)
}

Figura 1.7. Documento de uma coleção de álbuns musicais.

Embora o código da Figura 1.8 funcione corretamente, ele pode tornar-se lento a
medida que a quantidade de documentos crescer, devido a ter um laço dentro de outro.
Nos SGBDRs esse problema pode ser resolvido facilmente com um Join. Mas no Mon-
goDB não há Join ou operação semelhante. Para resolver esse problema, pode ser feito o
processo de desnormalização dos dados utilizando aninhamentos, que é bastante comum
nos bancos orientados a documentos. O aninhamento consiste em ter uma coleção den-
tro da outra. Na Figura 1.9 há um exemplo de aninhamento, no qual um documento da
var albuns = db.albuns.find({});
albuns.forEach(function(album) {
var genero = db.generos.findOne({"_id": album["id_genero"]});
print(album["nome"], genero["nome"]);
});

Figura 1.8. Código para buscar todos os álbuns e seus respectivos gêneros musicais.

coleção de gêneros está como um campo de um documento da coleção de álbuns. Obvi-


amente, desnormalizar dados pode gerar inconsistências. Além de tornar as atualizações
mais difíceis, documentos aninhados requerem mais espaço físico. Uma boa abordagem
para solucionar o problema de escolher entre referências ou documentos aninhados é usar
referência para criar um relacionamento e aninhar apenas os dados mais frequentemente
acessados de um documento. Contudo, a solução mais apropriada depende do sistema a
ser modelado.

{
"_id": ObjectId("63c828b5342dda43e93bee1e"),
"nome_album": "Legião Urbana
"duracao": 3286
"genero": {
"_id": ObjectId("54d1562cf7bb967d7b976d07"),
"nome_genero": "MPB
}
}

Figura 1.9. Documento aninhado de álbuns com gêneros musicais.

1.2.3.2. Bancos de dados NoSQL chave-valor

O modelo chave-valor (key-value) é considerado simples e permite a visualização do


banco de dados como uma grande tabela hash, que é uma estrutura de dados especial
que associa chaves de pesquisa a valores. De maneira bem simples, o banco de dados é
composto por um conjunto de chaves, as quais estão associadas a um único valor. Como
consequência da estrutura simples de armazenamento, os bancos de dados chave-valor
são completamente livres de esquema, ou seja, novos valores de qualquer tipo podem ser
adicionados.
A simplicidade deste modelo também permite que os dados sejam rapidamente
acessados pela chave, especialmente em sistemas que oferecem uma alta escalabilidade,
possibilitando, assim, o aumento da disponibilidade de acesso. Existem alguns proble-
mas comuns em que a solução mais prática é usar um banco key/value. Um exemplo é
compartilhar os dados de sessão de usuário entre vários servidores de aplicação, conhe-
cido como session storage. Outra exemplo em aplicação web é para armazenar pedaços
de HTML dinâmico pré-processados, evitando acesso ao disco e processamento de tem-
plates em todas as requisições, conhecido como fragment cache ou page cache. Alguns
bancos que utilizam esse padrão são: DynamoDb, Couchbase, Riak, Azure Table Storage,
Redis, Tokyo Cabinet, Berkeley DB. Nessa seção serão mostrados exemplos práticos de
como modelar, consultar e recuperar dados no banco de dados chave-valor Riak.
Riak é um bando de dados NoSQL chave-valor que oferece alta disponibilidade,
tolerância a faltas, operacionalidade simples e escalabilidade. Além de possuir um mo-
delo de replicação de dados muito avançado que possibilita uma configuração muito fle-
xível entre disponibilidade, consistência e latência; o Riak é um projeto de código aberto,
escrito em Erlang, com distribuição para Linux e MacOS.
Para criar um objeto no Riak, são necessário de três valores: chave, valor e bucket.
Com um bucket, Riak possibilita uma separação entre as chaves de diferentes aplicações
em um mesmo cluster, semelhante a um namespace. Na primeira linha da Figura 1.10
é criado um objeto no Riak que representa um bucket chamado de bucket01 com chave
chave01 e valor valor01. Esse objeto é armazenado na variável chamada de variavel01.
O comando put, da segunda linha da Figura 1.10, armazena o objeto de variavel01 no
banco utilizando a conexão da variável conexao01, obtida anteriormente. A execução
das operações da Figura 1.10 é similar a da SQL da Figura 1.11. Adicionalmente, Riak
disponibiliza uma interface HTTP para manipular dados. A Figura 1.12 mostra uma
requisição que é equivalente aos comandos da Figura 1.10. Essa requisição é feita através
de um PUT com o comando curl em um terminal, mas também poderia ser feita em um
navegador web através de um método POST ou PUT.

variavel01 = riak_object:new («"bucket01»>, «"chave01»>, «"valor01»>)


conexao01:put (variavel01, 1)

Figura 1.10. Comandos para inserir um objeto no Riak.

INSERT INTO bucket01 (chave, valor) VALUES ("chave01", "valor01")

Figura 1.11. Comando SLQ para inserir um elemento em SGBD relacional.

curl -XPUT -d "valor01"http://localhost:8098/types/default/buckets/bucket01/keys/chave01

Figura 1.12. Interface HTTP para inserir um objeto no Riak.

Os comandos da Figura 1.13 mostram como recuperar um valor de uma chave em


um bucket. Na primeira linha da Figura 1.13, a função get, utilizando a conexão cone-
xao01, retorna o objeto armazenado referente aos valores bucket01 e chave01. Caso o
objeto seja encontrado, ele será atribuído a variável resultado01. A segunda linha extrai o
valor de resultado01 através do comando riak_object:get_value. A execução dos coman-
dos da Figura 1.13 é similar a da SQL na Figura 1.14. A requisição da Figura 1.15 obtem
um valor equivalente a execução dos comandos da Figura 1.13.

ok, resultado01 = conexao01:get («"bucket01»>, «"valor01»>, 1)


riak_object:get_value (resultado01)

Figura 1.13. Comandos para selecionar um objeto no Riak.

SELECT valor FROM bucket01 WHERE chave01 = ’valor01’

Figura 1.14. Comando SLQ para selecionar um elemento em SGBD relacional.

curl http://localhost:8098/types/default/buckets/bucket01/keys/chave01

Figura 1.15. Interface HTTP para selecionar um objeto no Riak.

1.2.3.3. Bancos de dados NoSQL colunar

O modelo orientado a coluna utiliza-se de tabelas para representação de entidades e os da-


dos são gravados em disco agrupados por coluna, o que reduz o tempo de leitura e escrita
em disco. Os bancos colunares são os que mais se assemelham aos bancos relacionais
por terem uma tabela, mesmo que, na verdade eles sejam muito diferentes. São exemplos
de bancos orientados a coluna: Hbase, Cassandra, Hypertable, Accumulo, Amazon Sim-
pleDB, Cloudata, Cloudera, SciDB, HPCC, Stratosphere. Nessa seção serão mostrados
exemplos práticos de como modelar, consultar e recuperar dados no banco de dados co-
lunar Cassandra. Esse banco possui distribuições para Windows, Mac e Linus; e precisa
da máquina virtual Java para executar.
O Cassandra utiliza o conceito de keyspace, que é similar a um database, onde
tabelas são agrupadas para uma finalidade específica, geralmente para separar dados de
aplicações diferentes. Outro conceito importante é o de família de colunas (column fa-
mily) que é semelhante a uma entidade. Nas versões mais recentes do Cassandra o termo
família de colunas foi substituído por tabela. Esse banco utiliza a linguagem CQL (Cas-
sandra Query Language) que é semelhante a SQL dos bancos relacionais. A Figura 1.16
mostra como criar uma tabela no Cassandra através do comando CREAT TABLE, no qual
é criada uma tabela de filmes. Os comandos SELECT, INSERT, UPDATE e DELETE
também são utilizados de forma idêntica a SQL.
CREATE TABLE filmes(
videoId uuid,
nome_filme varchar,
descricao varchar,
localizacao_imagem_capa text,
data timestamp,
PRIMARY KEY(videoId)
);

Figura 1.16. Criação da tabela no Cassandra.

Apesar da sintaxe da busca no Cassandra ser idêntica a da busca nos bancos rela-
cionais, diferentemente deles, o Cassandra não faz buscas em campos que não possuem
índices. Nos bancos relacionais, apesar de não ser performático, esse tipo de busca fun-
ciona. Porém, por causa da maneira como Cassandra organiza os dados, uma busca por
campos sem índices seria tão ineficiente que ele prefere não suportar. Para ilustrar melhor
essa situação, na Figura 1.17 há uma consulta em CQL que não será executada se não for
criado um índice na coluna filtrada (como mostrado na Figura 1.18).

SELECT * FROM filmes WHERE nome = ’Matrix’

Figura 1.17. Busca utilizando um filtro no Cassandra.

CREATE INDEX ON filmes (nome)

Figura 1.18. Criação de um índice no Cassandra.

A tabela criada na Figura 1.16 é muito semelhante a uma tabela no modelo re-
lacinaol, entretanto, o modelo de dados utilizado comumente em bancos colunares é o
baseado em colunas dinâmicas (dynamic columns). Nesse modelo, as tabelas são scha-
meless, nas quais uma linha é chamada de partição (partition). Cada partição possui
sua chave única (partition key) que , a partir desta chave, podem ser adicionados vários
pares chave/valor que são chamados de pares coluna/linha (colunm/row). E cada par co-
luna/linha em uma partição é chamado de célula (cell). As células de uma mesma partição
são gravadas agrupadas para reduzir o tempo de leitura e escrita em disco. A Figura 1.19
mostra como os dados são organizados nas colunas dinâmicas do Cassandra.
Para criar uma tabela com colunas dinâmicas é necessário utilizar o parâmetro
WITH COMPACT STORAGE na criação da tabela. Além disso, a tabela deve possuir,
pelo menos, três colunas: uma que será a chave da partição; uma que será o nome da
coluna dinâmica e a última que será o valor da linha. Adicionalmente, a chave pri-
mária deve ser uma chave composta entre a chave da partição e o nome da coluna. A
Figura 1.20 exemplifica como criar uma tabela com coluna dinâmicas. Nesse exem-
plo, a tabela filmes_assistidos terá o campo userId como chave de partição; os campos
watch_date e videoId como nome da coluna dinâmica e; os campos nome_filme e loca-
lizacao_imagem_capa como valores da linha. Nessa tabela, os campos nome_filme e lo-
calizacao_imagem_capa são campos provenientes da tabela filmes (Figura 1.16). Como
Cassandra não tem nenhum conceito de integridade referencial e, portanto, não possui
join; nesse caso, foi necessário desnormalizar os dados para que uma busca na tabela
filmes_assistidos seja mais rápida, não necessitando de acessos a tabela filmes. Como
já dito anteriormente, a linguagem CQL do Cassandra é muito semelhante a SQL dos
bancos relacionais, mesmo que a organização dos dados nos dois tipos de bancos sejam
bem diferentes, como mostrado na figura 1.19. Isso foi feito para que os programado-
res acostumados com SQL utilizem CQL mais facilmente. Em versões mais antigas do
Cassandra, era permitido acessar as coluna dinâmicas de forma semelhante aos dados nos
bancos chave/valor.

Figura 1.19. Colunas dinâmicas no Cassandra.

CREATE TABLE filmes_assistidos(


userId uuid,
watch_date timestamp,
videoId uuid,
nome_filme varchar,
localizacao_imagem_capa text,
PRIMARY KEY (userId, watch_date, videoId)
) WITH COMPACT STORAGE;

Figura 1.20. Criação de tabela com colunas dinâmicas no Cassandra.

1.2.3.4. Bando de dados NoSQL orientado a grafos

Os bancos de dados do orientados a grafos possuem estruturas de dados modeladas na


forma de grafos, e a manipulação de dados é expressa através de operações orientadas a
grafos. Com isso, eles abstraem a complexidade dessas estruturas provendo ferramentas
para explorar o potencial delas. Nesses bancos, os dados são representados por nós, ares-
tas e propriedades; não há tabelas. Os nós representam as entidades, as arestas expressam
as relações entre os nós e as propriedades apresentam características das entidades e re-
lacionamentos. As bases de dados orientadas a grafos processam com eficiência densos
conjuntos de dados e o seu design permite a construção de modelos preditivos e análise
de correlações e de padrões de dados. Seguem as principais vantagens de se utilizar o
modelo orientado a grafos:

• alto desempenho independentemente do tamanho total do conjunto de dados (ga-


rantido pelas travessias nos grafos);

• o modelo de grafos aproxima os domínios técnicos e de negócios facilitando a mo-


delagem dos dados e;

• facilidade de se alterar o esquema de dados incluindo novas entidades e relaciona-


mentos sem a necessidade de reestruturar o esquema de dados.

Eexemplos de bancos orientados a grafos são: Neo4J, Infinite Graph, Sones, Info-
Grid, HyperGraphDB, DEX, Trinity, AllegroGraph, BrightStarDB, BigData, Meronymy,
OpenLink Virtuoso, VertexDB, FlockDB. Nessa seção serão mostrados exemplos práti-
cos de como modelar, consultar e recuperar dados no banco de dados orientado a grafos
Neo4j. Ele pode ser executado na máquina virtual Java e possui distribuições para Win-
dows, Mac e Linux. Semelhantemente a outros bancos orientados a grafos, Neo4j pode
ser aplicado a problemas que envolvem gerenciamento de rede, softwares analíticos, pes-
quisa cientifica, roteamento, gestão organizacional e de projeto, recomendações, redes
sociais e etc..
No Neor4j, cada nó criado pode ter um tipo e propriedades associadas a esse nó.
Na Figura 1.21 são criados dois nós que representam pessoas. Os dois nós são do tipo
Pessoa e possuem as propriedades nome e idade, além disso, estão associados as variáveis
neo e smith. Para exibir os nós inseridos, deve ser utilizado o comando MATCH que seria
equivalente ao SELECT em SQL. Além do MATCH, a outra parte obrigatória em um
comando de busca é o RETURN, que é usado para especificar o que será retornado. O
comando da Figura 1.22 busca por todos os nós do tipo Pessoa retornado seus nomes.
Para fins ilustrativos, SQL da Figura 1.23 é equivalente ao comando da Figura 1.22.

CREATE (neo:Pessoa {nome:’Neo’,idade: 29};)


CREATE (smith:Pessoa {nome:’Agente Smith’,idade: 36};)

Figura 1.21. Criação de nós no Neo4j.

Após nós terem sido criados, são necessárias arestas (relacionamentos) para dar
forma ao grafo. Na Figura 1.24 é mostrado como criar um relacionamento no Neo4j.
Primeiro, dois nós já existentes são buscados e armazenados nas variáveis p1 e p2 através
do comando MATCH. Em seguida, é criado um relacionamento entre p1 e p2 através do
comando CREATE, no qual é atribuído a propriedade CONHECE.
MATCH (m:Pessoa)
RETURN m.nome

Figura 1.22. Seleção de nós no Neo4j.

SELECT m.nome FROM Pessoa m

Figura 1.23. Seleção em SGBDRs.

MATCH (p1:Pessoa nome : ’Neo’ ),


(p2:Pessoa nome : ’Agente Smith’)
CREATE (p1)-[:CONHECE]->(P2)

Figura 1.24. Criação de relacionamento no Neo4j.

1.3. Estratégias de otimização de bancos de dados NoSQL


Exitem vários fatores que podem influenciar o desempenho e tempo de resposta de bancos
de dados, tais como: indexação, escrita de consultas, configurações do sistema e projeto
do banco de dados. Esta seção descreve técnicas para melhorar o desempenho de apli-
cações que utilizam banco de dados MongoDB. Os resultados dos exemplos mostrados
foram obtidos utilizando a ferramenta RoboMongo, uma ferramenta cliente para acessar
o MongoDB.

1.3.1. Análise de desempenho


Para um bom desempenho em aplicações que usam MongoBD é necessário analisar o
desempenho do sistema. Quando há uma queda no desempenho, geralmente, ocorre em
função de fatores, como: falta de estratégias de acesso eficientes; pouca disponibilidade
de hardware; número excessivo de conexões abertas ou; projetos inadequados. Seguem
algumas considerações sobre alguns dos fatores que podem influenciar no desempenho
do banco de dados.

1.3.1.1. Bloqueios

Bloqueios são utilizados para manter a consistência dos dados. Por exemplo, se algum
usuário desejar modificar determinado dado, o banco deve bloquear esse dado antes da
modificação para impedir que outros usuários sobrescrevam as alterações dele sobre o
dado. É certo que operações longas de bloqueio podem gerar longas filas de espera por
acesso a dados, podendo degradar drasticamente o desempenho de um sistema.
O MongoDB possui uma maneira para verificar os bloqueios no sistema através do
comando serverStatus. Esse comando fornece uma visão geral do sistema com informa-
ções sobre: o servidor onde o banco de dados está instalado, configurações de segurança,
armazenamento, memória, conexões, rede, bloqueios, dentre outras. A Figura 1.25 ilustra
como utilizar o comando serverStatus. Através de serverStatus podem ser obtidos infor-
mações gerais sobre bloqueios ou informações mais específicas sobre os bloqueis através
dos atributos globalLock e locks, respectivamente. A Figura 1.26 mostra um exemplo de
informações obtidas pelo comando serverStatus.

db.serverStatus()

Figura 1.25. Comando que retorna informações com uma visão geral sobre o
estado do sistema.

Figura 1.26. Informações gerais sobre o sistema obtidas através do comando


serverStatus.

1.3.1.2. Memória

MMAPv1 é o módulo responsável pelo gerenciamento de memória no MongoDB. Dado


um conjunto de dados, o módulo irá alocar toda a memória necessária a esses dados no
sistema. O comando serverStatus (ver Figura 1.25) exibe em seu atributo men (ver Figura
1.26) a quantidade de memória em uso e a quantidade de memória mapeada no sistema,
dentre outras informações.
Se a quantidade de memória mapeada for maior que a quantidade de memória fí-
sica disponível, poderão ocorrer page faults. Uma page fault acontece quando um dado
que deve ser acessado não está localizado correntemente na memória física e é necessário
fazer aceso ao disco. Muitas page faults podem prejudicar o desempenho do sistema. O
atributo extra_info de serverStatus possui informações sobre as page faults ocorridas no
MongoDB. O amento da quantidade de memória RAM pode ajudar a reduzir a frequência
de page faults. Mas, se isso não é possível, a implementação de um cluster (ou adição de
um novo nó em um cluster já implantado) pode resolver o problema através do comparti-
lhamento de dados e de recursos disponíveis.

1.3.1.3. Número de conexões abertas

Em alguns casos, o número de conexões entre as aplicações e o banco de dados pode


prejudicar a habilidade do servidor em responder as requisições. Se, em dado momento,
o número de requisições for muito grande, o sistema poderá ter problema em atendê-
las. Nesse caso, é necessário aumentar os recursos do servidor. Em um banco de dados,
implantado em um cluster, com problemas em atender a muitas conexões, se há muitas
aplicações requisitando leituras, é necessário aumentar o tamanho do conjunto de nós
réplicas para distribuir o processamento entre os membros do cluster. Por outro lado,
se há muitas aplicações requisitando escritas, é necessário aumentar o número de nós de
compartilhamento para dividir a carga de trabalho entre as instâncias do banco.

1.3.2. Avaliação de desempenho


Essa seção descreve estratégias para avaliar o desempenho de operações no MongoDB
atavés de: armazenamento de funções lentas; verificação de operações em processo de
execução e; verificação de plano de execução de consulta.

1.3.2.1. Armazenamento de operações lentas

A ferramenta Database Profiler pode ajudar na identificação de operações lentas no sis-


tema armazenando-as para que possam ser analisadas posteriormente. Ela possui níveis
de configuração mostrados na Tabela 1.1.

Tabela 1.1. Níveis de configuração do Database Profiler.


Nível Configuração
0 Não armazena nada.
1 Armazena apenas as operações lentas.
2 Armazena todas as operações.

Para configurar o nível de armazenamento de operações no Database Profiler é


utilizando o comando setProfilingLevel, como ilustrado no exemplo da Figura 1.27, onde
o número 1 (um) indica que foi escolhido por armazenar apenas as operações lentas do
sistema. Opcionalmente, em setProfilingLevel, pode ser passado um segundo parâmetro
numérico (em milissegundos) para informar qual o tempo mínimo que Database Profiler
deve considerar como necessário para uma operação ser lenta. Por padrão, uma operação
é considera lenta se executar em, pelo menos, 100ms. A Figura 1.28 mostra como obter as
operações armazenadas por Database Profiler utilizando o comando system.profile.find.
A Figura 1.29 mostra um exemplo de operações que podem ser armazenadas por Data-
base Profiler (obtidas pelo comando da Figura 1.28), no qual a segunda operação está
expandida e é possível observar que ela se trata de uma consulta feita sobre a coleção foo
do banco test.

db.setProfilingLevel( 1 )

Figura 1.27. Comando de configuração do Database Profiler para armazenar ope-


rações lentas.

db.system.profile.find()

Figura 1.28. Comando que lista as operações armazenadas pelo Database Profiler

Figura 1.29. Operações armazenadas em Database Profiler.

Database Profiler deve ser utilizado com cuidado, pois pode afetar negativamente
no desempenho do sistema. Por isso, deve ser ativado apenas em intervalos de tempo
estratégicos que não prejudiquem (ou prejudiquem minimamente) o sistema em produção.

1.3.2.2. Operações em processo de execução

Quando o sistema está lendo, uma das atividades que podem ser realizadas para resolver
o problema é verificar as operações que estão em execução. O método currentOp retorna
as operações que estão em processo de execução no MongoDb. Sem nenhum parâmetro,
currentOp retorna apenas as operações importantes correntemente em execução. Opci-
onalmente, esse comando pode ter os parâmetros, exibidos na Tabela 1.2, que o fazem
retornar conjuntos de operações diferentes.

Tabela 1.2. Parâmetros do método currentOp.


Parâmetro Retorno
true Todas as operações, incluindo as de sistema e conexões ociosas.
registro BSON Conjunto de operações especificadas no registro.

Na Figura 1.30, há o comando para listar todas as operações que estão sendo exe-
cutadas pelo sistema. A Figura 1.31 mostra todas as operações em execução no MongoDB
(retornadas utilizando o comando da Figura 1.30), na qual a operação 6 está expandida
exibindo informações sobre uma operação de conexão chamada de conn3 cujo atributo
active está com o valor false, indicando que a conexão está ociosa.

db.currentOp( true )

Figura 1.30. Comando que lista todas as operações em execução no sistema.

Figura 1.31. Operações em execução no sistema.

Utilizando um BSON como parâmetro, currentOp pode ser configurado para res-
tringir sua busca por: operações que estejam esperando por um bloqueio; operações ativas
sem rendimento; operações ativas em um banco de dados específico; operações que uti-
lizam índices; dentre outras. O comando da Figura 1.32 exibirá apenas as operações em
execução que estão esperando por um bloqueio:
db.currentOp( true ) {
"waitingForLock": true,
$or: [ "op": { "$in": [ "insert", "update", "remove"] } },
{ "query.findandmodify": { $exists: true } }
]
}

Figura 1.32. BSON de configuração no comando currentOp para restringir sua


busca as operações em execução que estão esperando por um bloqueio.

1.3.2.3. Plano de execução de consulta

O comando explain retorna informações sobre o plano de execução de uma consulta se-
lecionado pelo otimizador, como, índices utilizados, por exemplo. Além disso, explain
pode retornar informações estatísticas sobre o plano de execução da consulta. As infor-
mações retornadas por esse comando dependem dos parâmetros passados, descritos na
Tabela 1.3.

Tabela 1.3. Modos de execução do comando explain


Parâmetro Retorno
queryPlanner Informações sobre o plano de execução escolhido.
Informações sobre o plano de execução escolhido, incluindo
executionStats
suas informações estatísticas.
Informações sobre o plano de execução escolhido e informações
allPlansExecution estatísticas desse plano e de outros planos de execução
encontrados pelo otimizador no processo de seleção.

Caso nenhum parâmetro seja passado, explain utiliza queryPlanner como modo
padrão de execução. A Figura 1.33 mostra como explain pode ser utilizado (no modo
padrão: queryPlanner) para retornar o plano de execução escolhido pelo otimizador para
uma consulta cuja execução retorna todas a tuplas da coleção foo. A Figura 1.34 exibe o
plano de execução da consulta da Figura 1.33 no qual a estratégia utilizada para retornar as
tuplas foi CollScan (percorrer a coleção inteira). A utilização de explain, como mostrado
na Figura 1.33, funciona apenas para consultas. Para obter o plano de execução das
operações aggregate, count, distinct, find, group, remove e update; deve ser utilizado
db.collection.explain, ilustrado na Figura 1.35.

db.foo.find().explain()

Figura 1.33. Comando explain executando sob uma consulta.


Figura 1.34. Plano de execução de consulta.

db.products.explain().remove( { category: "apparel"}, { justOne: true } )

Figura 1.35. Plano de execução de uma comando de remoção.

1.3.3. Otimização do desempenho de consultas


1.3.3.1. Criação de índices

Índices são estruturas que utilizam estratégias de acesso rápido aos dados que referen-
ciam. Consultas lentas podem ter um melhor desempenho se índices forem criados para
suas atributos, visto que, percorrer índices é mais rápido do que uma coleção de dados.
A Figura 1.36 exemplifica como criar um índice para o campo author_name da coleção
posts.

db.posts.createIndex( { author_name : 1 } )

Figura 1.36. Comando para criação de um índice.

1.3.3.2. Limite o número de resultados de uma consulta

Limitar o número de resultados de uma consulta é uma boa estratégia para reduzir a
demanda de recursos trafegados pela rede. Retornar todos os dados de uma consulta
pode ser desnecessário. Às vezes, o usuário pode não precisar utilizar todas as linhas
retornadas por uma consulta ou carregar todas as linhas de uma consultas de uma só vez
pode prejudicar a visualização dos resultados. No MongoDB o número de resultados de
uma consulta pode ser limitado utilizando a função limit cujo funcionamento é similar ao
do comando Limit no SQL. Na Figura 1.38 há um exemplo de como utilizar limit para
uma consulta retornar apenas os 10 primeiros elementos.

db.posts.find().limit( 10 ) )

Figura 1.37. Comando para limitar a quantidade de documentos retornados por


uma busca.

1.3.3.3. Uso de projeções

O uso de projeções permite que um subconjunto dos campos de uma coleção seja retor-
nado por uma consulta. Retornar apenas os campos necessários pode trazer ganhos de
desempenho a uma consulta. Por exemplo, a consulta na Figura 1.38 retorna apenas os
campos timestamp, title, author, e abstract da coleção posts.

db.posts.find({},
{ timestamp : 1 ,
title : 1 ,
author : 1 ,
abstract : 1 }
).sort( { timestamp : -1 } )

Figura 1.38. Consulta com uso de projeção.

1.3.3.4. Uso de hints

Geralmente o otimizador seleciona os índices mais adequados à execução de uma con-


sulta. Entretanto, o uso de hints pode forçar o otimizador a selecionar determinados
índices para a execução de uma consulta. A consulta da Figura 1.39 possui um hint que
faz a consulta utilizar o índice do campo age da coleção users. Alternativamente, um hint
pode especificar o nome do índice a ser utilizado na execução de uma consulta. A Figura
1.40 ilustra um hint que força a consulta sobre a coleção users a utilizar o índice chamado
de age_1.

db.users.find().hint( { age: 1 } )

Figura 1.39. Hint para forçar uma consulta a utilizar um índice de um determinado
campo de uma coleção.
db.users.find().hint( "age_1")

Figura 1.40. Hint para forçar uma consulta a utilizar um determinado índice.

1.3.4. Desafios e problemas em aberto


Este módulo apresenta os desafios de adoção de NoSQL em ambientes tradicionais de
desenvolvimento de sistemas baseados na tecnologia relacional e as principais soluções e
pesquisas realizadas pela indústria e meio acadêmico.
No survey "Survey on NoSQL database" os autores descrevem o background, ca-
racterísticas básicas e modelagem de dados em NoSQL. Adicionalmente, o artigo classi-
fico os banco de dados NoSQL de acordo com o teorema CAP. Finalmente, os banco de
dados NoSQL mais convencionais são descritos em detalhes e extraídas algumas propri-
edade de modo a ajudar empresas a escolher o banco mais apropriado [4].
Em "Will NoSQL databases live up to their promise?" são discutidas questões
como limitações, vantagens, preocupações e dúvidas sobre os bancos de dados NoSQL
[5].
No artigo "Scalable SQL and NoSQL data stores" são examinadas SQL de aplica-
ções OLPT com bancos NoSQL. Os sistemas são comparados com relação a modelagem
de dados, consistência, armazenamento, durabilidade, disponibilidade e outra dimensões
[2].
Em "SQL databases v. NoSQL databases" são feitas comparações entre os bancos
de dados tradicionais e os bancos NoSQL mostrando vantagens do uso de NoSQL [10].
O trabalho "ShuttleDB: Database-Aware Elasticity in the Cloud" propõem um
database-aware para migração e replicação em bancos de dados em nuvem multi-tenant
de forma não intrusiva [1].
O paper "A comparison between several NoSQL databases with comments and
notes" faz uma comparação entre os bancos Cassandra, HBase e MySQ utilizando os
seguintes critérios: persistência, replicação, alta dispoibilidade, transações, localização,
linguagem de implementação, tipo de licença [12].
O trabalho desenvolvido em "Auto-tuning of Cloud-based In-memory Transactio-
nal Data Grids via Machine Learning" usa redes neurais para configurar dinamicamente
parâmetros de grids, reconfigurar automaticamente o número de servidores de cache e o
grau de replicação dos dados para maximizar/minimizar as métricas de performance [3].

Referências
[1] Barker, Sean Kenneth, et al. "ShuttleDB: Database-Aware Elasticity in the
Cloud."ICAC. 2014.
[2] Cattell, Rick. "Scalable SQL and NoSQL data stores."Acm Sigmod Record (2011).
[3] Di Sanzo, Pierangelo, et al. "Auto-tuning of cloud-based in-memory transactio-
nal data grids via machine learning."Network Cloud Computing and Applications
(NCCA), 2012 Second Symposium on IEEE, 2012.

[4] Han, Jing, et al. "Survey on NoSQL database."Pervasive computing and applications
(ICPCA), 6th international conference on. IEEE, 2011.

[5] Leavitt, Neal. "Will NoSQL databases live up to their promise?"Computer 43.2
(2010).

[6] Mohammad, M. Sc Siba. "Self-tuning for Cloud Database Clusters."Tese, Otto-von-


Guericke University Magdeburg, 2016.

[7] MongoDB Documentation. "https://docs.mongodb.com"Visitado in 2017.

[8] Paniz, David. "NoSQL: como armazenar dados de uma aplicação moderna."Casa do
Código, 2016.

[9] Souza, Alexandre Morais, et al. "Critérios para Seleção de SGBD NoSQL: o Ponto
de Vista de Especialistas com base na Literatura."Anais do X Simpósio Brasileiro
de Sistemas de Informação, Londrina-PR, Brasil (2014).

[10] Stonebraker, Michael. "SQL databases vs. NoSQL databases."Communications of


the ACM (2010).

[11] Toth, Renato Molina. "Abordagem NoSQL: uma real alternativa."Sorocaba, São
Paulo, Brasil (2011).

[12] Tudorica, Bogdan George, and Cristian Bucur. "A comparison between several
NoSQL databases with comments and notes."Roedunet International Conference
(RoEduNet), 10th IEEE, 2011.

[13] Vieira, Marcos Rodrigues, et al. "Bancos de Dados NoSQL: conceitos, ferramen-
tas, linguagens e estudos de casos no contexto de Big Data."Simpósio Brasileiro de
Bancos de Dados (2012).

Você também pode gostar