Ciao amici. Prima di partire per la seconda parte delle vacanze di maggio, condividiamo con voi il materiale che abbiamo tradotto in previsione del lancio di un nuovo stream sul corso
Gli sviluppatori di applicazioni trascorrono molto tempo confrontando più database operativi per selezionare quello più adatto al carico di lavoro previsto. Le esigenze possono includere modellazione dei dati semplificata, garanzie transazionali, prestazioni di lettura/scrittura, scalabilità orizzontale e tolleranza agli errori. Tradizionalmente, la scelta inizia con la categoria del database, SQL o NoSQL, poiché ciascuna categoria presenta una serie chiara di compromessi. Le prestazioni elevate in termini di bassa latenza e throughput elevato sono generalmente viste come un requisito senza compromessi e sono quindi essenziali per qualsiasi database di esempio.
Lo scopo di questo articolo è aiutare gli sviluppatori di applicazioni a fare la scelta giusta tra SQL e NoSQL nel contesto della modellazione dei dati delle applicazioni. Esamineremo un database SQL, ovvero PostgreSQL, e due database NoSQL, Cassandra e MongoDB, per coprire le basi della progettazione di database, come creare tabelle, popolarle, leggere dati da una tabella ed eliminarla. Nel prossimo articolo esamineremo sicuramente indici, transazioni, JOIN, direttive TTL e progettazione di database basata su JSON.
Qual è la differenza tra SQL e NoSQL?
I database SQL aumentano la flessibilità dell'applicazione attraverso le garanzie transazionali ACID, nonché la loro capacità di eseguire query sui dati utilizzando JOIN in modi inaspettati oltre ai modelli di database relazionali normalizzati esistenti.
Data la loro architettura monolitica/a nodo singolo e l'uso di un modello di replica master-slave per la ridondanza, i database SQL tradizionali mancano di due caratteristiche importanti: scalabilità di scrittura lineare (ovvero partizionamento automatico su più nodi) e perdita di dati automatica/zero. Ciò significa che la quantità di dati ricevuti non può superare il throughput massimo di scrittura di un singolo nodo. Inoltre, una certa perdita temporanea di dati deve essere presa in considerazione nella tolleranza agli errori (in un'architettura senza condivisione). Qui è necessario tenere presente che i commit recenti non si sono ancora riflessi nella copia slave. Anche gli aggiornamenti senza tempi di inattività sono difficili da ottenere nei database SQL.
I database NoSQL sono generalmente distribuiti per natura, ad es. in essi, i dati sono divisi in sezioni e distribuiti su più nodi. Richiedono la denormalizzazione. Ciò significa che i dati inseriti dovranno essere copiati anche più volte per rispondere alle specifiche richieste da te inviate. L'obiettivo generale è ottenere prestazioni elevate riducendo il numero di shard disponibili durante le letture. Ciò implica che NoSQL richiede che tu modelli le tue query, mentre SQL richiede che tu modelli i tuoi dati.
NoSQL si concentra sul raggiungimento di prestazioni elevate in un cluster distribuito e questa è la logica alla base di molti compromessi nella progettazione di database che includono perdita di transazioni ACID, JOIN e indici secondari globali coerenti.
Si sostiene che, sebbene i database NoSQL forniscano scalabilità di scrittura lineare e elevata tolleranza agli errori, la perdita di garanzie transazionali li rende inadatti per dati mission-critical.
La tabella seguente mostra le differenze tra la modellazione dei dati in NoSQL e SQL.
SQL e NoSQL: perché sono necessari entrambi?
Le applicazioni del mondo reale con un gran numero di utenti, come Amazon.com, Netflix, Uber e Airbnb, hanno il compito di eseguire attività complesse e sfaccettate. Ad esempio, un'applicazione di e-commerce come Amazon.com deve archiviare dati leggeri e altamente critici come informazioni sugli utenti, prodotti, ordini, fatture, insieme a dati pesanti e meno sensibili come recensioni di prodotti, messaggi di supporto, attività degli utenti, recensioni e consigli degli utenti. Naturalmente queste applicazioni si basano su almeno un database SQL insieme ad almeno un database NoSQL. Nei sistemi interregionali e globali, un database NoSQL funziona come una cache geograficamente distribuita per i dati archiviati in un database SQL di origine attendibile in esecuzione in una particolare regione.
In che modo YugaByte DB combina SQL e NoSQL?
Costruito su un motore di archiviazione misto orientato ai log, partizionamento automatico, replica di consenso distribuito frammentato e transazioni distribuite ACID (ispirate a Google Spanner), YugaByte DB è il primo database open source al mondo che è contemporaneamente compatibile con NoSQL (Cassandra e Redis) e SQL (PostgreSQL). Come mostrato nella tabella seguente, YCQL, l'API YugaByte DB compatibile con Cassandra, aggiunge i concetti di transazioni ACID a chiave singola e multichiave e indici secondari globali all'API NoSQL, inaugurando così l'era dei database NoSQL transazionali. Inoltre, YCQL, l'API YugaByte DB compatibile con PostgreSQL, aggiunge i concetti di scalabilità lineare della scrittura e tolleranza agli errori automatica all'API SQL, portando i database SQL distribuiti nel mondo. Poiché YugaByte DB è di natura transazionale, l'API NoSQL può ora essere utilizzata nel contesto di dati mission-critical.
Come già detto nell'articolo
- Se il tuo carico di lavoro principale è costituito da operazioni JOIN multi-chiave, quando scegli YSQL, tieni presente che le tue chiavi potrebbero essere distribuite su più nodi, con conseguente latenza più elevata e/o throughput inferiore rispetto a NoSQL.
- Altrimenti, scegli una delle due API NoSQL, tenendo presente che otterrai prestazioni migliori come risultato delle query servite da un nodo alla volta. YugaByte DB può fungere da unico database operativo per applicazioni complesse del mondo reale che devono gestire più carichi di lavoro contemporaneamente.
Il laboratorio di modellazione dei dati nella sezione successiva si basa sui database YugaByte DB compatibili con le API PostgreSQL e Cassandra, anziché sui database nativi. Questo approccio enfatizza la facilità di interazione con due API diverse (su due porte diverse) dello stesso cluster di database, invece di utilizzare cluster completamente indipendenti di due database diversi.
Nelle sezioni seguenti, daremo uno sguardo al laboratorio di modellazione dei dati per illustrare le differenze e alcuni punti in comune dei database trattati.
Laboratorio di modellazione dei dati
Installazione della banca dati
Data l'enfasi sulla progettazione del modello di dati (piuttosto che su complesse architetture di distribuzione), installeremo i database in contenitori Docker sul computer locale e quindi interagiremo con essi utilizzando le rispettive shell della riga di comando.
Database YugaByte DB compatibile 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
Accesso alla riga di comando
Colleghiamoci ai database utilizzando la shell della riga di comando per le API corrispondenti.
PostgreSQL
docker exec -it yb-postgres-n1 /home/yugabyte/postgres/bin/psql -p 5433 -U postgres
Cassandra
cqlsh
nel catalogo bin
.
Tieni presente che CQL è stato ispirato da SQL e ha concetti simili di tabelle, righe, colonne e indici. Tuttavia, essendo un linguaggio NoSQL, aggiunge una certa serie di limitazioni, la maggior parte delle quali tratteremo anche in altri articoli.
docker exec -it yb-tserver-n1 /home/yugabyte/bin/cqlsh
MongoDB
docker exec -it my-mongo bash
cd bin
mongo
Crea una tabella
Ora possiamo interagire con il database per eseguire varie operazioni utilizzando la riga di comando. Iniziamo creando una tabella che memorizza le informazioni sulle canzoni scritte da diversi artisti. Queste canzoni potrebbero far parte di un album. Anche gli attributi opzionali per una canzone sono l'anno di uscita, il prezzo, il genere e la valutazione. Dobbiamo tenere conto degli attributi aggiuntivi che potrebbero essere necessari in futuro attraverso il campo "tag". Può archiviare dati semistrutturati sotto forma di coppie chiave-valore.
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
La creazione di una tabella in Cassandra è molto simile a PostgreSQL. Una delle differenze principali è la mancanza di vincoli di integrità (ad esempio NOT NULL), ma questa è responsabilità dell'applicazione, non del database NoSQL. La chiave primaria è costituita da una chiave di partizione (la colonna Artista nell'esempio seguente) e da un insieme di colonne di clustering (la colonna SongTitle nell'esempio seguente). La chiave di partizione determina in quale partizione/frammento deve essere posizionata la riga e le colonne di clustering indicano come devono essere organizzati i dati all'interno del frammento corrente.
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 organizza i dati in database (Database) (simili al Keyspace di Cassandra), dove sono presenti Collezioni (simili a tabelle) che contengono Documenti (simili alle righe di una tabella). In MongoDB non è praticamente necessario definire uno schema iniziale. Squadra "usa banca dati", mostrato di seguito, crea un'istanza del database alla prima chiamata e modifica il contesto per il database appena creato. Anche le raccolte non necessitano di essere create esplicitamente; vengono create automaticamente, semplicemente quando aggiungi il primo documento a una nuova raccolta. Tieni presente che MongoDB utilizza il database di test per impostazione predefinita, quindi qualsiasi operazione a livello di raccolta senza specificare un database specifico verrà eseguita su di esso per impostazione predefinita.
use myNewDatabase;
Ottenere informazioni su una tabella
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;
Immissione di dati in una tabella
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
Espressione complessiva INSERT
in Cassandra sembra molto simile a quello in PostgreSQL. Tuttavia, c’è una grande differenza nella semantica. A Cassandra INSERT
è in realtà un'operazione UPSERT
, dove gli ultimi valori vengono aggiunti alla riga se la riga esiste già.
L'immissione dei dati è simile a PostgreSQL
INSERT
sopra
.
MongoDB
Anche se MongoDB è un database NoSQL come Cassandra, la sua operazione di inserimento non ha nulla in comune con il comportamento semantico di Cassandra. In MongoDB UPSERT
, che lo rende simile a PostgreSQL. Aggiunta di dati predefiniti senza _idspecified
farà sì che un nuovo documento venga aggiunto alla raccolta.
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"
}
}
);
Interrogazione tabella
Forse la differenza più significativa tra SQL e NoSQL in termini di costruzione delle query è il linguaggio utilizzato FROM
и WHERE
. SQL consente l'espressione successiva FROM
seleziona più tabelle ed espressione con WHERE
può essere di qualsiasi complessità (comprese le operazioni JOIN
tra i tavoli). Tuttavia, NoSQL tende a imporre una severa limitazione FROM
e funziona solo con una tabella specificata e in WHERE
, la chiave primaria deve essere sempre specificata. Ciò si collega alla spinta prestazionale NoSQL di cui abbiamo parlato in precedenza. Questo desiderio porta a ogni possibile riduzione di qualsiasi interazione tra tabelle e chiavi. Può introdurre un notevole ritardo nella comunicazione tra nodi quando si risponde a una richiesta ed è quindi meglio evitarlo in generale. Ad esempio, Cassandra richiede che le query siano limitate a determinati operatori (only =, IN, <, >, =>, <=
) sulle chiavi di partizione, tranne quando si richiede un indice secondario (qui è consentito solo l'operatore =).
PostgreSQL
Di seguito sono riportati tre esempi di query che possono essere facilmente eseguite da un database SQL.
- Visualizza tutte le canzoni per artista;
- Visualizza tutti i brani dell'artista che corrispondono alla prima parte del titolo;
- Visualizza tutte le canzoni di un artista che hanno una determinata parola nel titolo e hanno un prezzo inferiore 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
Delle query PostgreSQL elencate sopra, solo la prima funzionerà invariata in Cassandra, poiché l'operatore LIKE
non può essere applicato a colonne di clustering come SongTitle
. In questo caso sono ammessi solo gli operatori =
и 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
Come mostrato negli esempi precedenti, il metodo principale per creare query in MongoDB è music
nell'esempio seguente), quindi è vietato eseguire query su più raccolte.
db.music.find( {
artist: "No One You Know"
}
);
db.music.find( {
artist: "No One You Know",
songTitle: /Call/
}
);
Leggere tutte le righe di una tabella
La lettura di tutte le righe è semplicemente un caso speciale del modello di query esaminato in precedenza.
PostgreSQL
SELECT *
FROM Music;
Cassandra
Simile all'esempio PostgreSQL sopra.
MongoDB
db.music.find( {} );
Modifica dei dati in una tabella
PostgreSQL
PostgreSQL fornisce istruzioni UPDATE
per modificare i dati. Non ha opportunità UPSERT
, quindi questa istruzione fallirà se la riga non è più nel database.
UPDATE Music
SET Genre = 'Disco'
WHERE Artist = 'The Acme Band' AND SongTitle = 'Still In Love';
Cassandra
Cassandra sì UPDATE
simile a PostgreSQL. UPDATE
ha la stessa semantica UPSERT
, Piace INSERT
.
Simile all'esempio PostgreSQL sopra.
MongoDB
Operazione UPSERT
. Aggiornamento di più documenti e comportamenti simili UPSERT
può essere applicato impostando flag aggiuntivi per l'operazione. Ad esempio, nell'esempio seguente, il genere di un artista specifico viene aggiornato in base alla sua canzone.
db.music.update(
{"artist": "The Acme Band"},
{
$set: {
"genre": "Disco"
}
},
{"multi": true, "upsert": true}
);
Rimozione di dati da una tabella
PostgreSQL
DELETE FROM Music
WHERE Artist = 'The Acme Band' AND SongTitle = 'Look Out, World';
Cassandra
Simile all'esempio PostgreSQL sopra.
MongoDB
MongoDB ha due tipi di operazioni per eliminare i documenti −
db.music.deleteMany( {
artist: "The Acme Band"
}
);
Eliminazione di una tabella
PostgreSQL
DROP TABLE Music;
Cassandra
Simile all'esempio PostgreSQL sopra.
MongoDB
db.music.drop();
conclusione
Il dibattito sulla scelta tra SQL e NoSQL infuria da più di 10 anni. Ci sono due aspetti principali in questo dibattito: l'architettura del motore di database (SQL monolitico, transazionale rispetto a NoSQL distribuito e non transazionale) e l'approccio alla progettazione del database (modellazione dei dati in SQL rispetto alla modellazione delle query in NoSQL).
Con un database transazionale distribuito come YugaByte DB, il dibattito sull'architettura del database può essere facilmente messo a tacere. Man mano che i volumi di dati diventano più grandi di quelli che possono essere scritti su un singolo nodo, diventa necessaria un'architettura completamente distribuita che supporti la scalabilità di scrittura lineare con sharding/ribilanciamento automatico.
Inoltre, come affermato in uno degli articoli
Tornando alla discussione sulla progettazione di database, è giusto dire che entrambi gli approcci di progettazione (SQL e NoSQL) sono necessari per qualsiasi applicazione complessa del mondo reale. L'approccio di "modellazione dei dati" SQL consente agli sviluppatori di soddisfare più facilmente i mutevoli requisiti aziendali, mentre l'approccio di "modellazione delle query" NoSQL consente agli stessi sviluppatori di operare su grandi volumi di dati con bassa latenza e throughput elevato. È per questo motivo che YugaByte DB fornisce API SQL e NoSQL in un nucleo comune, anziché promuovere uno degli approcci. Inoltre, fornendo compatibilità con i linguaggi di database più diffusi tra cui PostgreSQL e Cassandra, YugaByte DB garantisce che gli sviluppatori non debbano imparare un altro linguaggio per lavorare con un motore di database distribuito e altamente coerente.
In questo articolo, abbiamo esaminato le differenze tra i fondamenti della progettazione di database tra PostgreSQL, Cassandra e MongoDB. Negli articoli futuri approfondiremo concetti di progettazione avanzati come indici, transazioni, JOIN, direttive TTL e documenti JSON.
Vi auguriamo un buon proseguimento di fine settimana e vi invitiamo a farlo
Fonte: habr.com