Olá amigos. Antes de partirmos para a segunda parte das férias de maio, compartilhamos com vocês o material que traduzimos em antecipação ao lançamento de uma nova stream do curso
Os desenvolvedores de aplicativos gastam muito tempo comparando vários bancos de dados operacionais para selecionar aquele que melhor se adapta à carga de trabalho pretendida. As necessidades podem incluir modelagem de dados simplificada, garantias transacionais, desempenho de leitura/gravação, escalabilidade horizontal e tolerância a falhas. Tradicionalmente, a escolha começa com a categoria do banco de dados, SQL ou NoSQL, já que cada categoria apresenta um conjunto claro de compensações. O alto desempenho em termos de baixa latência e alto rendimento é geralmente visto como um requisito sem compromisso e, portanto, essencial para qualquer banco de dados de amostra.
O objetivo deste artigo é ajudar os desenvolvedores de aplicativos a fazer a escolha certa entre SQL e NoSQL no contexto da modelagem de dados de aplicativos. Veremos um banco de dados SQL, chamado PostgreSQL, e dois bancos de dados NoSQL, Cassandra e MongoDB, para cobrir os conceitos básicos do design de banco de dados, como criar tabelas, preenchê-las, ler dados de uma tabela e excluí-los. No próximo artigo, veremos índices, transações, JOINs, diretivas TTL e design de banco de dados baseado em JSON.
Qual é a diferença entre SQL e NoSQL?
Os bancos de dados SQL aumentam a flexibilidade dos aplicativos por meio de garantias transacionais ACID, bem como sua capacidade de consultar dados usando JOINs de maneiras inesperadas, além de modelos de bancos de dados relacionais normalizados existentes.
Dada a sua arquitetura monolítica/nó único e o uso de um modelo de replicação mestre-escravo para redundância, os bancos de dados SQL tradicionais carecem de dois recursos importantes: escalabilidade de gravação linear (ou seja, particionamento automático em vários nós) e perda automática/zero de dados. Isso significa que a quantidade de dados recebidos não pode exceder o rendimento máximo de gravação de um único nó. Além disso, alguma perda temporária de dados deve ser levada em consideração na tolerância a falhas (em uma arquitetura sem compartilhamento). Aqui você precisa ter em mente que os commits recentes ainda não foram refletidos na cópia escrava. Atualizações sem tempo de inatividade também são difíceis de obter em bancos de dados SQL.
Os bancos de dados NoSQL são geralmente distribuídos por natureza, ou seja, neles, os dados são divididos em seções e distribuídos por vários nós. Eles exigem desnormalização. Isso significa que os dados inseridos também devem ser copiados diversas vezes para responder às solicitações específicas que você enviar. O objetivo geral é obter alto desempenho reduzindo o número de shards disponíveis durante as leituras. Isso implica que o NoSQL exige que você modele suas consultas, enquanto o SQL exige que você modele seus dados.
O NoSQL se concentra em alcançar alto desempenho em um cluster distribuído e esta é a justificativa subjacente para muitas compensações no design de banco de dados que incluem perda de transações ACID, JOINs e índices secundários globais consistentes.
Há um argumento de que, embora os bancos de dados NoSQL forneçam escalabilidade de gravação linear e alta tolerância a falhas, a perda de garantias transacionais os torna inadequados para dados de missão crítica.
A tabela a seguir mostra como a modelagem de dados no NoSQL difere do SQL.
SQL e NoSQL: por que ambos são necessários?
Aplicativos do mundo real com grande número de usuários, como Amazon.com, Netflix, Uber e Airbnb, têm a tarefa de realizar tarefas complexas e multifacetadas. Por exemplo, um aplicativo de comércio eletrônico como Amazon.com precisa armazenar dados leves e altamente críticos, como informações do usuário, produtos, pedidos, faturas, junto com dados pesados e menos confidenciais, como análises de produtos, mensagens de suporte, atividade do usuário, comentários e recomendações de usuários. Naturalmente, esses aplicativos dependem de pelo menos um banco de dados SQL junto com pelo menos um banco de dados NoSQL. Em sistemas inter-regionais e globais, um banco de dados NoSQL opera como um cache distribuído geograficamente para dados armazenados em um banco de dados SQL de origem confiável executado em uma região específica.
Como o YugaByte DB combina SQL e NoSQL?
Construído em um mecanismo de armazenamento misto orientado a log, fragmentação automática, replicação de consenso distribuída fragmentada e transações distribuídas ACID (inspirado no Google Spanner), YugaByte DB é o primeiro banco de dados de código aberto do mundo que é simultaneamente compatível com NoSQL (Cassandra & Redis) e SQL (PostgreSQL). Conforme mostrado na tabela abaixo, YCQL, a API YugaByte DB compatível com Cassandra, adiciona os conceitos de transações ACID de chave única e múltipla e índices secundários globais à API NoSQL, inaugurando assim a era dos bancos de dados NoSQL transacionais. Além disso, YCQL, a API YugaByte DB compatível com PostgreSQL, adiciona os conceitos de escala de gravação linear e tolerância automática a falhas à API SQL, trazendo bancos de dados SQL distribuídos para o mundo. Como o YugaByte DB é de natureza transacional, a API NoSQL agora pode ser usada no contexto de dados de missão crítica.
Como dito anteriormente no artigo
- Se sua carga de trabalho principal for operações JOIN com várias chaves, ao escolher YSQL, entenda que suas chaves podem ser distribuídas entre vários nós, resultando em maior latência e/ou menor rendimento do que NoSQL.
- Caso contrário, escolha uma das duas APIs NoSQL, tendo em mente que você obterá melhor desempenho como resultado de consultas atendidas em um nó por vez. O YugaByte DB pode servir como um único banco de dados operacional para aplicativos complexos do mundo real que precisam gerenciar várias cargas de trabalho simultaneamente.
O laboratório de modelagem de dados na próxima seção é baseado em bancos de dados YugaByte DB compatíveis com PostgreSQL e Cassandra API, em oposição a bancos de dados nativos. Esta abordagem enfatiza a facilidade de interação com duas APIs diferentes (em duas portas diferentes) do mesmo cluster de banco de dados, em vez de usar clusters completamente independentes de dois bancos de dados diferentes.
Nas seções a seguir, daremos uma olhada no laboratório de modelagem de dados para ilustrar as diferenças e alguns pontos em comum dos bancos de dados abordados.
Laboratório de Modelagem de Dados
Instalação de banco de dados
Dada a ênfase no design do modelo de dados (em vez de arquiteturas de implantação complexas), instalaremos bancos de dados em contêineres Docker na máquina local e, em seguida, interagiremos com eles usando seus respectivos shells de linha de comando.
Banco de dados YugaByte DB compatível com PostgreSQL e Cassandra
mkdir ~/yugabyte && cd ~/yugabyte
wget https://downloads.yugabyte.com/yb-docker-ctl && chmod +x yb-docker-ctl
docker pull yugabytedb/yugabyte
./yb-docker-ctl create --enable_postgres
MongoDB
docker run --name my-mongo -d mongo:latest
Acesso à linha de comando
Vamos nos conectar aos bancos de dados usando o shell de linha de comando para as APIs correspondentes.
PostgreSQL
docker exec -it yb-postgres-n1 /home/yugabyte/postgres/bin/psql -p 5433 -U postgres
Cassandra
cqlsh
no catálogo bin
.
Observe que o CQL foi inspirado no SQL e possui conceitos semelhantes de tabelas, linhas, colunas e índices. No entanto, como linguagem NoSQL, ela adiciona um certo conjunto de limitações, muitas das quais também abordaremos em outros artigos.
docker exec -it yb-tserver-n1 /home/yugabyte/bin/cqlsh
MongoDB
docker exec -it my-mongo bash
cd bin
mongo
Criar uma tabela
Agora podemos interagir com o banco de dados para realizar diversas operações usando a linha de comando. Vamos começar criando uma tabela que armazena informações sobre músicas escritas por diferentes artistas. Essas músicas podem fazer parte de um álbum. Também atributos opcionais para uma música são ano de lançamento, preço, gênero e classificação. Precisamos levar em conta atributos adicionais que podem ser necessários no futuro através do campo “tags”. Ele pode armazenar dados semiestruturados na forma de pares de valores-chave.
PostgreSQL
CREATE TABLE Music (
Artist VARCHAR(20) NOT NULL,
SongTitle VARCHAR(30) NOT NULL,
AlbumTitle VARCHAR(25),
Year INT,
Price FLOAT,
Genre VARCHAR(10),
CriticRating FLOAT,
Tags TEXT,
PRIMARY KEY(Artist, SongTitle)
);
Cassandra
Criar uma tabela no Cassandra é muito semelhante ao PostgreSQL. Uma das principais diferenças é a falta de restrições de integridade (por exemplo, NOT NULL), mas isso é responsabilidade da aplicação, não do banco de dados NoSQL. A chave primária consiste em uma chave de partição (a coluna Artista no exemplo abaixo) e um conjunto de colunas de cluster (a coluna SongTitle no exemplo abaixo). A chave de partição determina em qual partição/fragmento a linha deve ser colocada e as colunas de cluster indicam como os dados devem ser organizados no fragmento atual.
CREATE KEYSPACE myapp;
USE myapp;
CREATE TABLE Music (
Artist TEXT,
SongTitle TEXT,
AlbumTitle TEXT,
Year INT,
Price FLOAT,
Genre TEXT,
CriticRating FLOAT,
Tags TEXT,
PRIMARY KEY(Artist, SongTitle)
);
MongoDB
O MongoDB organiza os dados em bancos de dados (Database) (semelhante ao Keyspace no Cassandra), onde existem Coleções (semelhantes a tabelas) que contêm Documentos (semelhantes a linhas de uma tabela). No MongoDB, basicamente não há necessidade de definir um esquema inicial. Equipe "usar banco de dados", mostrado abaixo, instancia o banco de dados na primeira chamada e altera o contexto do banco de dados recém-criado. Mesmo as coleções não precisam ser criadas explicitamente; elas são criadas automaticamente, simplesmente quando você adiciona o primeiro documento a uma nova coleção. Observe que o MongoDB usa o banco de dados de teste por padrão, portanto, qualquer operação em nível de coleção sem especificar um banco de dados específico será executada nele por padrão.
use myNewDatabase;
Obtendo informações sobre uma tabela
PostgreSQL
d Music
Table "public.music"
Column | Type | Collation | Nullable | Default
--------------+-----------------------+-----------+----------+--------
artist | character varying(20) | | not null |
songtitle | character varying(30) | | not null |
albumtitle | character varying(25) | | |
year | integer | | |
price | double precision | | |
genre | character varying(10) | | |
criticrating | double precision | | |
tags | text | | |
Indexes:
"music_pkey" PRIMARY KEY, btree (artist, songtitle)
Cassandra
DESCRIBE TABLE MUSIC;
CREATE TABLE myapp.music (
artist text,
songtitle text,
albumtitle text,
year int,
price float,
genre text,
tags text,
PRIMARY KEY (artist, songtitle)
) WITH CLUSTERING ORDER BY (songtitle ASC)
AND default_time_to_live = 0
AND transactions = {'enabled': 'false'};
MongoDB
use myNewDatabase;
show collections;
Inserindo dados em uma tabela
PostgreSQL
INSERT INTO Music
(Artist, SongTitle, AlbumTitle,
Year, Price, Genre, CriticRating,
Tags)
VALUES(
'No One You Know', 'Call Me Today', 'Somewhat Famous',
2015, 2.14, 'Country', 7.8,
'{"Composers": ["Smith", "Jones", "Davis"],"LengthInSeconds": 214}'
);
INSERT INTO Music
(Artist, SongTitle, AlbumTitle,
Price, Genre, CriticRating)
VALUES(
'No One You Know', 'My Dog Spot', 'Hey Now',
1.98, 'Country', 8.4
);
INSERT INTO Music
(Artist, SongTitle, AlbumTitle,
Price, Genre)
VALUES(
'The Acme Band', 'Look Out, World', 'The Buck Starts Here',
0.99, 'Rock'
);
INSERT INTO Music
(Artist, SongTitle, AlbumTitle,
Price, Genre,
Tags)
VALUES(
'The Acme Band', 'Still In Love', 'The Buck Starts Here',
2.47, 'Rock',
'{"radioStationsPlaying": ["KHCR", "KBQX", "WTNR", "WJJH"], "tourDates": { "Seattle": "20150625", "Cleveland": "20150630"}, "rotation": Heavy}'
);
Cassandra
Expressão geral INSERT
no Cassandra é muito semelhante ao do PostgreSQL. No entanto, há uma grande diferença na semântica. Em Cassandra INSERT
na verdade é uma operação UPSERT
, onde os últimos valores são adicionados à linha se a linha já existir.
A entrada de dados é semelhante ao PostgreSQL
INSERT
acima
.
MongoDB
Embora o MongoDB seja um banco de dados NoSQL como o Cassandra, sua operação de inserção não tem nada em comum com o comportamento semântico do Cassandra. No MongoDB UPSERT
, o que o torna semelhante ao PostgreSQL. Adicionando dados padrão sem _idspecified
fará com que um novo documento seja adicionado à coleção.
db.music.insert( {
artist: "No One You Know",
songTitle: "Call Me Today",
albumTitle: "Somewhat Famous",
year: 2015,
price: 2.14,
genre: "Country",
tags: {
Composers: ["Smith", "Jones", "Davis"],
LengthInSeconds: 214
}
}
);
db.music.insert( {
artist: "No One You Know",
songTitle: "My Dog Spot",
albumTitle: "Hey Now",
price: 1.98,
genre: "Country",
criticRating: 8.4
}
);
db.music.insert( {
artist: "The Acme Band",
songTitle: "Look Out, World",
albumTitle:"The Buck Starts Here",
price: 0.99,
genre: "Rock"
}
);
db.music.insert( {
artist: "The Acme Band",
songTitle: "Still In Love",
albumTitle:"The Buck Starts Here",
price: 2.47,
genre: "Rock",
tags: {
radioStationsPlaying:["KHCR", "KBQX", "WTNR", "WJJH"],
tourDates: {
Seattle: "20150625",
Cleveland: "20150630"
},
rotation: "Heavy"
}
}
);
Consulta de tabela
Talvez a diferença mais significativa entre SQL e NoSQL em termos de construção de consultas seja a linguagem usada FROM
и WHERE
. SQL permite após expressão FROM
selecione várias tabelas e expressão com WHERE
pode ser de qualquer complexidade (incluindo operações JOIN
entre tabelas). No entanto, o NoSQL tende a impor uma limitação severa na FROM
, e trabalhar apenas com uma tabela especificada, e em WHERE
, a chave primária deve sempre ser especificada. Isso está relacionado ao impulso de desempenho do NoSQL de que falamos anteriormente. Esse desejo leva a todas as reduções possíveis em qualquer interação entre tabelas e chaves cruzadas. Pode introduzir um grande atraso na comunicação entre nós ao responder a uma solicitação e, portanto, é melhor evitá-lo em geral. Por exemplo, Cassandra exige que as consultas sejam limitadas a determinados operadores (apenas =, IN, <, >, =>, <=
) em chaves de partição, exceto ao solicitar um índice secundário (somente o operador = é permitido aqui).
PostgreSQL
Abaixo estão três exemplos de consultas que podem ser facilmente executadas por um banco de dados SQL.
- Exibir todas as músicas de um artista;
- Exibe todas as músicas do artista que correspondem à primeira parte do título;
- Exibe todas as músicas de um artista que possuem uma determinada palavra no título e têm preço inferior a 1.00.
SELECT * FROM Music
WHERE Artist='No One You Know';
SELECT * FROM Music
WHERE Artist='No One You Know' AND SongTitle LIKE 'Call%';
SELECT * FROM Music
WHERE Artist='No One You Know' AND SongTitle LIKE '%Today%'
AND Price > 1.00;
Cassandra
Das consultas PostgreSQL listadas acima, apenas a primeira funcionará inalterada no Cassandra, pois o operador LIKE
não pode ser aplicado a colunas de cluster, como SongTitle
. Neste caso, apenas operadores são permitidos =
и IN
.
SELECT * FROM Music
WHERE Artist='No One You Know';
SELECT * FROM Music
WHERE Artist='No One You Know' AND SongTitle IN ('Call Me Today', 'My Dog Spot')
AND Price > 1.00;
MongoDB
Conforme mostrado nos exemplos anteriores, o principal método para criar consultas no MongoDB é music
no exemplo abaixo), portanto é proibido consultar múltiplas coleções.
db.music.find( {
artist: "No One You Know"
}
);
db.music.find( {
artist: "No One You Know",
songTitle: /Call/
}
);
Lendo todas as linhas de uma tabela
A leitura de todas as linhas é simplesmente um caso especial do padrão de consulta que vimos anteriormente.
PostgreSQL
SELECT *
FROM Music;
Cassandra
Semelhante ao exemplo do PostgreSQL acima.
MongoDB
db.music.find( {} );
Editando dados em uma tabela
PostgreSQL
PostgreSQL fornece instruções UPDATE
para alterar dados. Ela não tem oportunidades UPSERT
, portanto, esta instrução falhará se a linha não estiver mais no banco de dados.
UPDATE Music
SET Genre = 'Disco'
WHERE Artist = 'The Acme Band' AND SongTitle = 'Still In Love';
Cassandra
Cassandra tem UPDATE
semelhante ao PostgreSQL. UPDATE
tem a mesma semântica UPSERT
, como INSERT
.
Semelhante ao exemplo do PostgreSQL acima.
MongoDB
Operação UPSERT
. Atualizando vários documentos e comportamento semelhante UPSERT
pode ser aplicado definindo sinalizadores adicionais para a operação. Por exemplo, no exemplo abaixo, o gênero de um artista específico é atualizado com base em sua música.
db.music.update(
{"artist": "The Acme Band"},
{
$set: {
"genre": "Disco"
}
},
{"multi": true, "upsert": true}
);
Removendo dados de uma tabela
PostgreSQL
DELETE FROM Music
WHERE Artist = 'The Acme Band' AND SongTitle = 'Look Out, World';
Cassandra
Semelhante ao exemplo do PostgreSQL acima.
MongoDB
MongoDB possui dois tipos de operações para excluir documentos -
db.music.deleteMany( {
artist: "The Acme Band"
}
);
Excluindo uma tabela
PostgreSQL
DROP TABLE Music;
Cassandra
Semelhante ao exemplo do PostgreSQL acima.
MongoDB
db.music.drop();
Conclusão
O debate sobre a escolha entre SQL e NoSQL já dura há mais de 10 anos. Existem dois aspectos principais neste debate: arquitetura do mecanismo de banco de dados (SQL monolítico, transacional versus NoSQL distribuído e não transacional) e abordagem de design de banco de dados (modelagem de seus dados em SQL versus modelagem de suas consultas em NoSQL).
Com um banco de dados transacional distribuído como o YugaByte DB, o debate sobre a arquitetura do banco de dados pode ser facilmente encerrado. À medida que os volumes de dados se tornam maiores do que o que pode ser gravado em um único nó, torna-se necessária uma arquitetura totalmente distribuída que suporte escalabilidade de gravação linear com fragmentação/rebalanceamento automático.
Além disso, como afirma um dos artigos
Voltando à discussão sobre design de banco de dados, é justo dizer que ambas as abordagens de design (SQL e NoSQL) são necessárias para qualquer aplicação complexa do mundo real. A abordagem de “modelagem de dados” SQL permite que os desenvolvedores atendam mais facilmente aos requisitos de negócios em constante mudança, enquanto a abordagem de “modelagem de consulta” NoSQL permite que os mesmos desenvolvedores operem em grandes volumes de dados com baixa latência e alto rendimento. É por esta razão que YugaByte DB fornece APIs SQL e NoSQL em um núcleo comum, em vez de promover uma das abordagens. Além disso, ao fornecer compatibilidade com linguagens de banco de dados populares, incluindo PostgreSQL e Cassandra, o YugaByte DB garante que os desenvolvedores não precisem aprender outra linguagem para trabalhar com um mecanismo de banco de dados distribuído e altamente consistente.
Neste artigo, vimos como os fundamentos do design de banco de dados diferem entre PostgreSQL, Cassandra e MongoDB. Em artigos futuros, mergulharemos em conceitos avançados de design, como índices, transações, JOINs, diretivas TTL e documentos JSON.
Desejamos-lhe um excelente resto de fim de semana e convidamo-lo a
Fonte: habr.com