Fundamentos de deseño de bases de datos: comparando PostgreSQL, Cassandra e MongoDB

Ola, amigos. Antes de marchar para a segunda parte das vacacións de maio, compartimos con vós o material que traducimos en previsión do lanzamento dun novo fluxo sobre o curso "DBMS relacional".

Fundamentos de deseño de bases de datos: comparando PostgreSQL, Cassandra e MongoDB

Os desenvolvedores de aplicacións pasan moito tempo comparando varias bases de datos operativas para seleccionar a que mellor se adapte á carga de traballo prevista. As necesidades poden incluír modelado de datos simplificado, garantías transaccionais, rendemento de lectura/escritura, escalado horizontal e tolerancia a fallos. Tradicionalmente, a elección comeza coa categoría de base de datos, SQL ou NoSQL, xa que cada categoría presenta un claro conxunto de compensacións. O alto rendemento en termos de baixa latencia e alto rendemento é xeralmente visto como un requisito non compensatorio e, polo tanto, é esencial para calquera base de datos de mostra.

O propósito deste artigo é axudar aos desenvolvedores de aplicacións a facer a elección correcta entre SQL e NoSQL no contexto do modelado de datos de aplicacións. Analizaremos unha base de datos SQL, a saber, PostgreSQL, e dúas bases de datos NoSQL, Cassandra e MongoDB, para cubrir os conceptos básicos do deseño de bases de datos, como crear táboas, enchelas, ler datos dunha táboa e eliminalas. No seguinte artigo, asegurarémonos de mirar índices, transaccións, JOIN, directivas TTL e deseño de bases de datos baseados en JSON.

Cal é a diferenza entre SQL e NoSQL?

As bases de datos SQL aumentan a flexibilidade das aplicacións grazas ás garantías transaccionais de ACID, así como a súa capacidade para consultar datos mediante JOIN de formas inesperadas ademais dos modelos de bases de datos relacionais normalizados existentes.

Dada a súa arquitectura monolítica/de nodo único e o uso dun modelo de replicación mestre-escravo para a redundancia, as bases de datos SQL tradicionais carecen de dúas características importantes: escalabilidade de escritura lineal (é dicir, partición automática en varios nodos) e perda automática/cero de datos. Isto significa que a cantidade de datos recibidos non pode superar o rendemento máximo de escritura dun só nodo. Ademais, hai que ter en conta algunha perda temporal de datos na tolerancia a fallos (nunha arquitectura de nada compartido). Aquí cómpre ter en conta que as confirmacións recentes aínda non se reflectiron na copia escrava. As actualizacións sen tempo de inactividade tamén son difíciles de conseguir nas bases de datos SQL.

As bases de datos NoSQL adoitan estar distribuídas por natureza, é dicir. neles, os datos divídense en seccións e distribúense en varios nodos. Requiren desnormalización. Isto significa que os datos introducidos tamén se deben copiar varias veces para responder ás solicitudes específicas que envíe. O obxectivo xeral é obter un alto rendemento reducindo o número de fragmentos dispoñibles durante as lecturas. Isto implica que NoSQL require que modeles as túas consultas, mentres que SQL require que modeles os teus datos.

NoSQL céntrase en lograr un alto rendemento nun clúster distribuído e esta é a razón subxacente para moitas compensacións de deseño de bases de datos que inclúen a perda de transaccións de ACID, JOINs e índices secundarios globais consistentes.

Hai un argumento de que aínda que as bases de datos NoSQL proporcionan escalabilidade de escritura lineal e alta tolerancia a fallos, a perda de garantías transaccionais fai que sexan inadecuadas para datos de misión crítica.

A seguinte táboa mostra como se diferencia o modelado de datos en NoSQL de SQL.

Fundamentos de deseño de bases de datos: comparando PostgreSQL, Cassandra e MongoDB

SQL e NoSQL: por que se necesitan ambos?

As aplicacións do mundo real con gran número de usuarios, como Amazon.com, Netflix, Uber e Airbnb, teñen a tarefa de realizar tarefas complexas e multifacéticas. Por exemplo, unha aplicación de comercio electrónico como Amazon.com necesita almacenar datos lixeiros e moi críticos, como información do usuario, produtos, pedidos, facturas, xunto con datos pesados ​​e menos sensibles, como recensións de produtos, mensaxes de asistencia, actividade do usuario, opinións e recomendacións dos usuarios. Por suposto, estas aplicacións dependen de polo menos unha base de datos SQL xunto con polo menos unha base de datos NoSQL. En sistemas interrexionais e globais, unha base de datos NoSQL funciona como unha caché xeodistribuída para os datos almacenados nunha base de datos SQL de orixe fiable que se executa nunha rexión concreta.

Como combina YugaByte DB SQL e NoSQL?

Construído sobre un motor de almacenamento mixto orientado ao rexistro, fragmentación automática, replicación de consenso distribuído fragmentado e transaccións distribuídas por ACID (inspirado en Google Spanner), YugaByte DB é a primeira base de datos de código aberto do mundo que é simultáneamente compatible con NoSQL (Cassandra e Redis) e SQL (PostgreSQL). Como se mostra na táboa seguinte, YCQL, a API de base de datos de YugaByte compatible con Cassandra, engade os conceptos de transaccións ACID de chave única e múltiple e índices secundarios globais á API de NoSQL, inaugurando así a era das bases de datos NoSQL transaccionais. Ademais, YCQL, a API YugaByte DB compatible con PostgreSQL, engade os conceptos de escalado de escritura lineal e tolerancia automática a fallos á API SQL, levando as bases de datos SQL distribuídas ao mundo. Debido a que YugaByte DB é de natureza transaccional, a API de NoSQL agora pódese usar no contexto de datos de misión crítica.

Fundamentos de deseño de bases de datos: comparando PostgreSQL, Cassandra e MongoDB

Como se dixo anteriormente no artigo "Presentación de YSQL: unha API de SQL distribuida compatible con PostgreSQL para YugaByte DB", a elección entre SQL ou NoSQL en YugaByte DB depende totalmente das características da carga de traballo subxacente:

  • Se a túa carga de traballo principal son as operacións JOIN de varias teclas, ao elixir YSQL, debes entender que as túas chaves poden estar distribuídas en varios nodos, o que resulta nunha maior latencia e/ou menor rendemento que NoSQL.
  • En caso contrario, escolla calquera das dúas API de NoSQL, tendo en conta que obterá un mellor rendemento como resultado das consultas servidas desde un nodo á vez. YugaByte DB pode servir como unha única base de datos operativa para aplicacións complexas e do mundo real que precisan xestionar varias cargas de traballo ao mesmo tempo.

O laboratorio de modelado de datos da seguinte sección baséase en bases de datos YugaByte DB compatibles con PostgreSQL e Cassandra API, en oposición ás bases de datos nativas. Este enfoque enfatiza a facilidade de interactuar con dúas API diferentes (en dous portos diferentes) do mesmo clúster de bases de datos, en oposición ao uso de clústeres completamente independentes de dúas bases de datos diferentes.
Nas seguintes seccións, botaremos unha ollada ao laboratorio de modelado de datos para ilustrar as diferenzas e algúns dos puntos comúns das bases de datos tratadas.

Laboratorio de Modelización de Datos

Instalación de base de datos

Dada a énfase no deseño de modelos de datos (en lugar de arquitecturas de implantación complexas), instalaremos bases de datos en contedores Docker na máquina local e, a continuación, interactuaremos con elas mediante as súas respectivas shells de liña de comandos.

Base de datos YugaByte DB compatible con 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

Acceso á liña de comandos

Conectámonos ás bases de datos usando o shell de liña de comandos para as API correspondentes.

PostgreSQL

psql é un shell de liña de comandos para interactuar con PostgreSQL. Para facilitar o seu uso, YugaByte DB vén con psql directamente no cartafol bin.

docker exec -it yb-postgres-n1 /home/yugabyte/postgres/bin/psql -p 5433 -U postgres

Cassandra

cqlsh é un shell de liña de comandos para interactuar con Cassandra e as súas bases de datos compatibles mediante CQL (Cassandra Query Language). Para facilitar o seu uso, inclúe YugaByte DB cqlsh no catálogo bin.
Teña en conta que CQL inspirouse en SQL e ten conceptos similares de táboas, filas, columnas e índices. Non obstante, como linguaxe NoSQL, engade un certo conxunto de limitacións, a maioría das cales tamén trataremos noutros artigos.

docker exec -it yb-tserver-n1 /home/yugabyte/bin/cqlsh

MongoDB

mongo é un shell de liña de comandos para interactuar con MongoDB. Pódese atopar no directorio bin da instalación de MongoDB.

docker exec -it my-mongo bash 
cd bin
mongo

Crea unha táboa

Agora podemos interactuar coa base de datos para realizar varias operacións mediante a liña de comandos. Comecemos creando unha táboa que almacene información sobre cancións escritas por diferentes artistas. Estas cancións poden formar parte dun álbum. Tamén os atributos opcionais dunha canción son o ano de lanzamento, o prezo, o xénero e a clasificación. Necesitamos ter en conta os atributos adicionais que poden ser necesarios no futuro a través do campo "etiquetas". Pode almacenar datos semiestruturados en forma de pares clave-valor.

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

Crear unha táboa en Cassandra é moi similar a PostgreSQL. Unha das principais diferenzas é a falta de restricións de integridade (por exemplo, NOT NULL), pero esta é responsabilidade da aplicación, non da base de datos NoSQL.. A clave principal consiste nunha chave de partición (a columna Artista no exemplo de abaixo) e un conxunto de columnas agrupadas (a columna SongTitle no exemplo de abaixo). A clave de partición determina en que partición/fragmento debe colocarse a fila e as columnas de agrupación indican como se deben organizar os datos dentro do fragmento actual.

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

MongoDB organiza os datos en bases de datos (base de datos) (semellante a Keyspace en Cassandra), onde hai Coleccións (similares ás táboas) que conteñen documentos (semellantes ás filas dunha táboa). En MongoDB, basicamente non hai necesidade de definir un esquema inicial. Equipo "usar base de datos", que se mostra a continuación, crea unha instancia da base de datos na primeira chamada e cambia o contexto para a base de datos recentemente creada. Incluso as coleccións non precisan ser creadas de forma explícita; créanse automaticamente, simplemente cando engades o primeiro documento a unha nova colección. Teña en conta que MongoDB usa a base de datos de proba por defecto, polo que calquera operación a nivel de colección sen especificar unha base de datos específica executarase nela por defecto.

use myNewDatabase;

Obtención de información sobre unha táboa
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;

Introducir datos nunha táboa
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

Expresión global INSERT en Cassandra é moi semellante ao de PostgreSQL. Non obstante, hai unha gran diferenza na semántica. En Cassandra INSERT é en realidade unha operación UPSERT, onde se engaden os últimos valores á fila se a fila xa existe.

A entrada de datos é similar a PostgreSQL INSERT anterior

.

MongoDB

Aínda que MongoDB é unha base de datos NoSQL como Cassandra, a súa operación de inserción non ten nada en común co comportamento semántico de Cassandra. En MongoDB insert () non ten oportunidades UPSERT, o que o fai similar a PostgreSQL. Engadir datos predeterminados sen _idspecified fará que se engada un novo documento á colección.

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 táboa

Quizais a diferenza máis significativa entre SQL e NoSQL en canto á construción de consultas sexa a linguaxe utilizada FROM и WHERE. SQL permite a expresión posterior FROM seleccionar varias táboas e expresión con WHERE pode ser de calquera complexidade (incluídas as operacións JOIN entre táboas). Non obstante, NoSQL tende a impoñer unha limitación severa FROM, e traballar só cunha táboa especificada e en WHERE, sempre debe especificarse a chave primaria. Isto está relacionado co impulso do rendemento de NoSQL do que falamos anteriormente. Este desexo leva a todas as posibles reducións de calquera interacción entre táboas e claves cruzadas. Pode introducir un gran atraso na comunicación entre nodos ao responder a unha solicitude e, polo tanto, é mellor evitarlo en xeral. Por exemplo, Cassandra require que as consultas estean limitadas a determinados operadores (só =, IN, <, >, =>, <=) nas claves de partición, excepto cando se solicita un índice secundario (aquí só se permite o operador =).

PostgreSQL

A continuación móstranse tres exemplos de consultas que se poden executar facilmente mediante unha base de datos SQL.

  • Mostrar todas as cancións dun artista;
  • Mostra todas as cancións do artista que coincidan coa primeira parte do título;
  • Mostra todas as cancións dun artista que teñan unha determinada palabra no título e teñan un prezo 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 anteriormente, só a primeira funcionará sen cambios en Cassandra, xa que o operador LIKE non se pode aplicar a agrupar columnas como SongTitle. Neste caso, só se permiten operadores = и 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

Como se mostra nos exemplos anteriores, o método principal para crear consultas en MongoDB é db.collection.find(). Este método contén explícitamente o nome da colección (music no exemplo seguinte), polo que está prohibido consultar varias coleccións.

db.music.find( {
  artist: "No One You Know"
 } 
);
db.music.find( {
  artist: "No One You Know",
  songTitle: /Call/
 } 
);

Lectura de todas as filas dunha táboa

A lectura de todas as filas é simplemente un caso especial do patrón de consulta que analizamos anteriormente.

PostgreSQL

SELECT * 
FROM Music;

Cassandra

Similar ao exemplo de PostgreSQL anterior.

MongoDB

db.music.find( {} );

Edición de datos nunha táboa

PostgreSQL

PostgreSQL proporciona instrucións UPDATE para cambiar datos. Ela non ten oportunidades UPSERT, polo que esta instrución fallará se a fila xa non está na base de datos.

UPDATE Music
SET Genre = 'Disco'
WHERE Artist = 'The Acme Band' AND SongTitle = 'Still In Love';

Cassandra

Cassandra ten UPDATE similar a PostgreSQL. UPDATE ten a mesma semántica UPSERT, semellante INSERT.

Similar ao exemplo de PostgreSQL anterior.

MongoDB
Funcionamento update () en MongoDB pode actualizar completamente un documento existente ou actualizar só certos campos. Por defecto, só actualiza un documento coa semántica desactivada UPSERT. Actualización de varios documentos e comportamento similar UPSERT pódese aplicar establecendo bandeiras adicionais para a operación. Por exemplo, no seguinte exemplo, o xénero dun artista específico actualízase en función da súa canción.

db.music.update(
  {"artist": "The Acme Band"},
  { 
    $set: {
      "genre": "Disco"
    }
  },
  {"multi": true, "upsert": true}
);

Eliminar datos dunha táboa

PostgreSQL

DELETE FROM Music
WHERE Artist = 'The Acme Band' AND SongTitle = 'Look Out, World';

Cassandra

Similar ao exemplo de PostgreSQL anterior.

MongoDB

MongoDB ten dous tipos de operacións para eliminar documentos − deleteOne() /deleteMany() и quitar(). Ambos tipos eliminan documentos pero devolven resultados diferentes.

db.music.deleteMany( {
        artist: "The Acme Band"
    }
);

Eliminar unha táboa

PostgreSQL

DROP TABLE Music;

Cassandra

Similar ao exemplo de PostgreSQL anterior.

MongoDB

db.music.drop();

Conclusión

O debate sobre a elección entre SQL e NoSQL leva máis de 10 anos. Hai dous aspectos principais neste debate: a arquitectura do motor de base de datos (monolítico, SQL transaccional vs distribuído, NoSQL non transacción) e o enfoque de deseño de base de datos (modelando os teus datos en SQL vs modelando as túas consultas en NoSQL).

Cunha base de datos transaccional distribuída como YugaByte DB, o debate sobre a arquitectura de bases de datos pódese deter facilmente. A medida que os volumes de datos se fan máis grandes do que se pode escribir nun só nodo, faise necesaria unha arquitectura totalmente distribuída que admita escalabilidade de escritura lineal con fragmentación/reequilibrio automático.

Ademais, como se indica nun dos artigos Google Cloud,As arquitecturas transaccionais e moi consistentes úsanse agora máis para proporcionar unha mellor axilidade de desenvolvemento que as arquitecturas non transacionais e, finalmente, coherentes.

Volvendo á discusión sobre o deseño da base de datos, é xusto dicir que os dous enfoques de deseño (SQL e NoSQL) son necesarios para calquera aplicación complexa do mundo real. O enfoque de "modelado de datos" de SQL permite aos desenvolvedores cumprir con máis facilidade os requisitos empresariais cambiantes, mentres que o enfoque de "modelo de consultas" de NoSQL permite aos mesmos desenvolvedores operar con grandes volumes de datos con baixa latencia e alto rendemento. É por esta razón que YugaByte DB ofrece API SQL e NoSQL nun núcleo común, en lugar de promover un dos enfoques. Ademais, ao proporcionar compatibilidade con linguaxes de bases de datos populares, incluíndo PostgreSQL e Cassandra, YugaByte DB garante que os desenvolvedores non teñan que aprender outro idioma para traballar cun motor de base de datos distribuído e altamente consistente.

Neste artigo, analizamos como os fundamentos do deseño de bases de datos difieren entre PostgreSQL, Cassandra e MongoDB. En artigos futuros, mergullaremos en conceptos de deseño avanzados como índices, transaccións, JOIN, directivas TTL e documentos JSON.

Desexámosvos un bo descanso da fin de semana e convidámosvos webinar gratuíto, que terá lugar o 14 de maio.

Fonte: www.habr.com

Engadir un comentario