Ciao, amici. Prima di partire per la seconda parte delle vacanze di maggio, condividiamo con voi un materiale che abbiamo tradotto in preparazione al lancio del nuovo corso. .

Gli sviluppatori di applicazioni spendono molto tempo a confrontare diversi database operativi per scegliere quello più adatto al carico di lavoro previsto. Le esigenze possono includere una modellazione dei dati semplificata, garanzie transazionali, prestazioni di lettura/scrittura, scalabilità orizzontale e resilienza. Tradizionalmente, la scelta inizia con la categoria del database, SQL o NoSQL, poiché ogni categoria offre un set chiaro di compromessi. Prestazioni elevate in termini di bassa latenza e alta larghezza di banda vengono generalmente considerate una necessità non negoziabile, rendendole quindi essenziali per qualsiasi database selezionato.
L'obiettivo 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, ossia PostgreSQL, e due database NoSQL: Cassandra e MongoDB, per discutere i fondamenti della progettazione di database, come la creazione di tabelle, il loro popolamento, la lettura dei dati dalle tabelle e la loro rimozione. 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 grazie alle garanzie transazionali ACID e alla loro capacità di interrogare i dati tramite JOIN in modi inaspettati sopra i modelli relazionali normalizzati esistenti.
Considerando la loro architettura monolitica/a nodi singoli e l'uso del modello di replicazione master-slave per la ridondanza, i tradizionali database SQL mancano di due importanti caratteristiche: scalabilità lineare in scrittura (ovvero la suddivisione automatica su più nodi) e perdita di dati automatica/zero. Ciò significa che la quantità di dati ricevuti non può superare la massima capacità di scrittura di un nodo. Inoltre, una certa perdita temporale di dati deve essere presa in considerazione in caso di fault tolerance (in un'architettura senza separazione delle risorse). Qui bisogna tenere a mente che gli ultimi commit non si riflettono ancora nella copia secondaria (slave). Le aggiornamenti senza downtime sono anche difficili da realizzare nei database SQL.
I database NoSQL sono per loro natura tipicamente distribuiti, il che significa che i dati sono suddivisi in sezioni e distribuiti su più nodi. Richiedono denormalizzazione. Ciò implica che i dati inseriti devono essere copiati più volte per rispondere a specifiche richieste che si inviano. L'obiettivo generale è ottenere alte prestazioni riducendo il numero di shard disponibili durante la lettura. Ne consegue che NoSQL richiede di modellare le proprie query, mentre SQL richiede di modellare i propri dati.
NoSQL si concentra sul raggiungimento di alte prestazioni in un cluster distribuito e questo è il principale giustificativo per molti compromessi nel design dei database, che includono la perdita delle garanzie di transazione ACID, i JOIN e gli indici secondari globali coerenti.
C'è un'opinione secondo cui, sebbene i database NoSQL forniscano scalabilità lineare in scrittura e alta tolleranza ai guasti, la perdita delle garanzie transazionali li rende inadatti per i dati critici.
La tabella seguente mostra come la modellazione dei dati in NoSQL differisca da SQL.

SQL e NoSQL: Perché è necessario entrambi?
Sulle applicazioni reali con un gran numero di utenti, come Amazon.com, Netflix, Uber e Airbnb, ricade l'esecuzione di compiti complessi e diversificati. Ad esempio, un'applicazione di e-commerce simile a Amazon.com deve gestire dati leggeri e altamente critici, come informazioni su utenti, prodotti, ordini e fatture, insieme a dati più pesanti, ma meno sensibili, come recensioni di prodotti, messaggi del servizio clienti, attività degli utenti, feedback e raccomandazioni. Naturalmente, queste applicazioni si basano almeno su un database SQL, insieme a almeno un database NoSQL. Nelle sistemi interregionali e globali, un database NoSQL funge da cache geodistribuita per i dati memorizzati in una fonte fidata, un database SQL operante in una specifica regione.
Come unisce YugaByte DB SQL e NoSQL?
Costruita su un motore ibrido orientato ai log per lo storage, auto-sharding, replica di consenso distribuita basata su sharding e transazioni distribuite ACID (ispirate a Google Spanner), YugaByte DB è il primo database open-source al mondo compatibile sia con NoSQL (Cassandra & Redis) sia con SQL (PostgreSQL). Come mostrato nella tabella qui sotto, YCQL, l'API di YugaByte DB compatibile con Cassandra, aggiunge concetti di transazioni ACID a chiave singola e multipla e indici secondari globali all'API NoSQL, aprendo così un'era di database NoSQL transazionali. Inoltre, YCQL, l'API di YugaByte DB compatibile con PostgreSQL, integra concetti di scalabilità lineare della scrittura e resilienza automatica nell'API SQL, presentando al mondo database SQL distribuiti. Poiché il database YugaByte DB è intrinsecamente transazionale, ora l'API NoSQL può essere utilizzata nel contesto di dati critici.

Come già menzionato nell'articolo , la scelta tra SQL o NoSQL in YugaByte DB dipende completamente dalle caratteristiche del carico di lavoro principale:
- Se il carico di lavoro principale consiste in operazioni multiple con JOIN, quando si sceglie YSQL, è importante considerare che le vostre chiavi possono essere distribuite su più nodi, il che comporterà una latenza più elevata e/o una diminuzione della larghezza di banda rispetto a NoSQL.
- In caso contrario, scegli uno dei due API NoSQL, tenendo presente che otterrai migliori prestazioni da richieste gestite da un singolo nodo alla volta. YugaByte DB può fungere da unico database operativo per applicazioni complesse reali in cui è necessario gestire più carichi di lavoro contemporaneamente.
Alla base del laboratorio di modellazione dei dati (Data modeling lab) nella seguente sezione ci sono database YugaByte DB compatibili con PostgreSQL e Cassandra, a differenza dei database di origine. Questo approccio sottolinea la semplicità di interazione con due API diverse (su due porte diverse) dello stesso cluster di database, rispetto all'uso di cluster completamente indipendenti di due database distinti.
Nelle prossime sezioni ci familiarizzeremo con il laboratorio di modellazione dei dati per illustrare le differenze e alcune somiglianze tra i database considerati.
Laboratorio di modellazione dei dati
Installazione dei database
Tenendo presente l'accento sulla progettazione del modello di dati (e non su architetture di distribuzione complesse), installeremo i database in contenitori Docker sul computer locale e poi interagirà con essi utilizzando le rispettive shell della riga di comando.
Database YugaByte DB compatibile con PostgreSQL & 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_postgresMongoDB
docker run --name my-mongo -d mongo:latestAccesso tramite riga di comando
Colleghiamoci ai database utilizzando la shell della riga di comando per le rispettive API.
PostgreSQL
è la shell della riga di comando per interagire con PostgreSQL. Per facilitare l'uso, YugaByte DB viene fornito con psql direttamente nella cartella bin.
docker exec -it yb-postgres-n1 /home/yugabyte/postgres/bin/psql -p 5433 -U postgresCassandra
è la shell della riga di comando per interagire con Cassandra e i suoi database compatibili tramite CQL (Cassandra Query Language). Per comodità, YugaByte DB viene fornito con cqlsh nella directory bin.
Nota che CQL è stato ispirato da SQL e ha concetti analoghi di tabelle, righe, colonne e indici. Tuttavia, essendo un linguaggio NoSQL, aggiunge un set di vincoli specifici, la maggior parte dei quali tratteremo anche in altri articoli.
docker exec -it yb-tserver-n1 /home/yugabyte/bin/cqlshMongoDB
– è una shell della riga di comando per interagire con MongoDB. Può essere trovata nella cartella bin dell'installazione di MongoDB.
docker exec -it my-mongo bash
cd bin
mongoCreazione della tabella
Ora possiamo interagire con il database per eseguire diverse operazioni tramite la riga di comando. Iniziamo con la creazione di una tabella che memorizza informazioni sulle canzoni scritte da vari artisti. Queste canzoni possono far parte di un album. Gli attributi opzionali per una canzone sono l'anno di pubblicazione, il prezzo, il genere e la valutazione. Dobbiamo considerare attributi aggiuntivi che potrebbero essere necessari in futuro, attraverso il campo "tag". Questo può memorizzare dati semi-strutturati in 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 principali differenze è l'assenza di vincoli di integrità (ad esempio, NOT NULL), ma questa è responsabilità dell'applicazione, e non del database NoSQL.. La chiave primaria è composta dalla chiave di partizione (la colonna Artist nell'esempio qui sotto) e da un insieme di colonne di clustering (la colonna SongTitle nell'esempio qui sotto). La chiave di partizione determina in quale partizione/shard collocare la riga, mentre le colonne di clustering indicano come devono essere organizzati i dati all'interno dello shard attuale.
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) (analogo a Keyspace in Cassandra), dove ci sono collezioni (Collections) (analogo a tabelle), contenenti documenti (Documents) (analogo a righe nella tabella). In MongoDB, non è necessario definire uno schema iniziale. Il comando "use database", mostrato di seguito, crea un'istanza del database alla prima chiamata e cambia il contesto per il database appena creato. Anche le collezioni non devono essere create esplicitamente, vengono create automaticamente semplicemente aggiungendo il primo documento a una nuova collezione. Si noti che MongoDB utilizza per impostazione predefinita un database di test, quindi qualsiasi operazione a livello di collezioni senza specificare un database specifico verrà eseguita su di esso per impostazione predefinita.
use myNewDatabase;Ottenere informazioni sulla tabella
PostgreSQL
d Musica
Tabella "public.music"
Colonna | Tipo | Ordinamento | Nullabile | Predefinito
--------------+-----------------------+-----------+----------+--------
artista | carattere variabile(20) | | non nullo |
titolo canzone | carattere variabile(30) | | non nullo |
titolo album | carattere variabile(25) | | |
anno | intero | | |
prezzo | precisione doppia | | |
genere | carattere variabile(10) | | |
valutazione critico | precisione doppia | | |
tags | testo | | |
Indici:
"music_pkey" CHIAVE PRIMARIA, btree (artista, titolo canzone)Cassandra
DESCRIVI TABELLA MUSICA;
CREA TABELLA myapp.music (
artista testo,
titolo canzone testo,
titolo album testo,
anno int,
prezzo float,
genere testo,
tags testo,
CHIAVE PRIMARIA (artista, titolo canzone)
) CON ORDINE DI CLUSTERING PER (titolo canzone ASC)
E default_time_to_live = 0
E transazioni = {'enabled': 'false'};MongoDB
usa myNewDatabase;
mostra collezioni;Inserimento dati nella tabella
PostgreSQL
INSERISCI IN Music
(Artista, TitoloCanzone, TitoloAlbum,
Anno, Prezzo, Genere, ValutazioneCritico,
Tags)
VALORI(
'No One You Know', 'Call Me Today', 'Somewhat Famous',
2015, 2.14, 'Country', 7.8,
'{"Composers": ["Smith", "Jones", "Davis"],"LengthInSeconds": 214}'
);
INSERISCI IN Music
(Artista, TitoloCanzone, TitoloAlbum,
Prezzo, Genere, ValutazioneCritico)
VALORI(
'No One You Know', 'My Dog Spot', 'Hey Now',
1.98, 'Country', 8.4
);
INSERISCI IN Music
(Artista, TitoloCanzone, TitoloAlbum,
Prezzo, Genere)
VALORI(
'The Acme Band', 'Look Out, World', 'The Buck Starts Here',
0.99, 'Rock'
);
INSERISCI IN Music
(Artista, TitoloCanzone, TitoloAlbum,
Prezzo, Genere,
Tags)
VALORI(
'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
In generale, l'espressione INSERISCI in Cassandra appare molto simile a quella in PostgreSQL. Tuttavia c'è una grande differenza nella semantica. In Cassandra INSERISCI è di fatto un'operazione UPSERT, dove nella riga vengono aggiunti i valori più recenti, nel caso in cui la riga esista già.
L'immissione dei dati avviene in modo simile a PostgreSQL
INSERISCIsopra
.
MongoDB
Nonostante MongoDB sia un database NoSQL, simile a Cassandra, la sua operazione di immissione dati non ha nulla a che fare con il comportamento semantico in Cassandra. In MongoDB non ha funzionalità UPSERT, il che lo rende simile a PostgreSQL. L'aggiunta di dati senza specificare _id porterà all'aggiunta di un nuovo documento nella collezione. Richiesta della tabella
db.music.insert( {
artista: "No One You Know",
titoloCanzone: "Chiamami Oggi",
titoloAlbum: "Un po' Famoso",
anno: 2015,
prezzo: 2.14,
genere: "Country",
tags: {
Compositori: ["Smith", "Jones", "Davis"],
DurataInSecondi: 214
}
}
);
db.music.insert( {
artista: "No One You Know",
titoloCanzone: "Il Mio Cane Spot",
titoloAlbum: "Hey Now",
prezzo: 1.98,
genere: "Country",
valutazioneCritica: 8.4
}
);
db.music.insert( {
artista: "The Acme Band",
titoloCanzone: "Guarda Fuori, Mondo",
titoloAlbum:"The Buck Starts Here",
prezzo: 0.99,
genere: "Rock"
}
);
db.music.insert( {
artista: "The Acme Band",
titoloCanzone: "Ancora In Amore",
titoloAlbum:"The Buck Starts Here",
prezzo: 2.47,
genere: "Rock",
tags: {
radioStazioniInRiproduzione:["KHCR", "KBQX", "WTNR", "WJJH"],
dateTour: {
Seattle: "20150625",
Cleveland: "20150630"
},
rotazione: "Pesante"
}
}
);
Potrebbe esserci una differenza sostanziale tra SQL e NoSQL dal punto di vista della formulazione delle richieste, che risiede nell'uso delle formulazioni
DA DA e DOVEdi selezionare più tabelle, mentre l'espressione con DA può avere qualsiasi complessità (inclusa l'operazione DOVE JOIN JOIN , e lavora solo con una tabella specificata, mentre DA, e lavora solo con una tabella specificata. DOVE, deve sempre essere specificata una chiave primaria. Questo è legato al desiderio di migliorare le prestazioni di NoSQL di cui abbiamo parlato in precedenza. Questo desiderio porta a ridurre al minimo qualsiasi interazione tra tabelle incrociate e chiavi incrociate. Può causare un'elevata latenza nella comunicazione tra nodi quando si risposta a una query e, di conseguenza, è meglio evitarlo in linea di principio. Ad esempio, Cassandra richiede che le query siano limitate a determinati operatori (sono permessi solo =, IN, , =>, <=) sulle chiavi delle partizioni, ad eccezione dei casi di query su indici secondari (qui è permesso solo l'operatore =).
PostgreSQL
Di seguito sono riportati tre esempi di query che possono essere eseguite facilmente in un database SQL.
- Elenca tutte le canzoni di un artista;
- Elenca tutte le canzoni di un artista che corrispondono alla prima parte del titolo;
- Elenca tutte le canzoni di un artista che contengono una certa 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
Tra le query sopra elencate, solo la prima funzionerà in Cassandra senza modifiche, poiché l'operatore LIKE non può essere applicato alle colonne di clustering, come SongTitle. In questo caso, sono consentiti solo gli operatori = e 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 è . Questo metodo contiene esplicitamente il nome della collezione (music nell'esempio seguente), quindi la query su più collezioni non è consentita.
db.music.find( {
artist: "No One You Know"
}
);
db.music.find( {
artist: "No One You Know",
songTitle: /Call/
}
);Lettura di tutte le righe della tabella
La lettura di tutte le righe è semplicemente un caso particolare di quel modello di query che abbiamo esaminato in precedenza.
PostgreSQL
SELECT *
FROM Music;Cassandra
Simile all'esempio in PostgreSQL sopra.
MongoDB
db.music.find( {} );Modifica dei dati nella tabella
PostgreSQL
PostgreSQL fornisce l'istruzione UPDATE per modificare i dati. Essa non ha capacità UPSERT, quindi l'esecuzione di questa istruzione genererà un errore se le righe non sono più presenti nel database.
UPDATE Music
SET Genre = 'Disco'
WHERE Artist = 'The Acme Band' AND SongTitle = 'Still In Love';Cassandra
In Cassandra c'è UPDATE un equivalente di PostgreSQL. UPDATE ha la stessa semantica UPSERT, simile a INSERISCI.
Simile all'esempio in PostgreSQL sopra.
MongoDB
Operazione In MongoDB è possibile aggiornare completamente un documento esistente o aggiornare solo determinati campi. Per impostazione predefinita, aggiorna solo un documento con la semantica disabilitata. UPSERT. L'aggiornamento di più documenti e il comportamento sono analoghi UPSERT e possono essere applicati impostando flag aggiuntivi per l'operazione. Come nell'esempio seguente, avviene l'aggiornamento del genere di un artista specifico in base alla sua canzone.
db.music.update(
{"artist": "The Acme Band"},
{
$set: {
"genre": "Disco"
}
},
{"multi": true, "upsert": true}
);Eliminazione dei dati da una tabella
PostgreSQL
DELETE FROM Music
WHERE Artist = 'The Acme Band' AND SongTitle = 'Look Out, World';Cassandra
Simile all'esempio in PostgreSQL sopra.
MongoDB
In MongoDB ci sono due tipi di operazioni per eliminare documenti — e . Entrambi i tipi eliminano documenti, ma restituiscono risultati diversi.
db.music.deleteMany( {
artist: "The Acme Band"
}
);
Eliminazione di una tabella
PostgreSQL
DROP TABLE Music;Cassandra
Simile all'esempio in PostgreSQL sopra.
MongoDB
db.music.drop();Conclusione
Le dispute sulla scelta tra SQL e NoSQL infuriano da oltre 10 anni. Ci sono due aspetti principali di questa disputa: l'architettura centrale del database (SQL monolitico e transazionale contro NoSQL distribuito e non transazionale) e l'approccio alla progettazione del database (modellazione dei dati in SQL contro modellazione delle tue query in NoSQL).
Con un database transazionale distribuito come YugaByte DB, i dibattiti riguardo all'architettura del database possono essere facilmente dissipati. Man mano che i volumi di dati superano ciò che può essere scritto in un singolo nodo, un'architettura completamente distribuita che supporta la scalabilità lineare della scrittura con partizionamento automatico/ri-bilanciamento diventa necessaria.
Oltre a quanto indicato in uno degli articoli , le architetture transazionali e rigorosamente coerenti sono ora più ampiamente utilizzate per garantire una maggiore flessibilità nello sviluppo rispetto a quelle non transazionali, coerentemente finali.
Tornando alla discussione sulla progettazione di database, è giusto dire che entrambi gli approcci progettuali (SQL e NoSQL) sono necessari per qualsiasi applicazione reale complessa. L'approccio SQL di "modellazione dei dati" consente agli sviluppatori di soddisfare più facilmente le mutevoli esigenze aziendali, mentre l'approccio NoSQL di "modellazione delle query" consente agli stessi sviluppatori di gestire grandi volumi di dati con bassa latenza e alta capacità. È per questo motivo che YugaByte DB offre API SQL e NoSQL in un unico nucleo, senza promuovere un approccio specifico. Inoltre, garantendo la compatibilità con i linguaggi di database più popolari, tra cui PostgreSQL e Cassandra, YugaByte DB assicura che gli sviluppatori non debbano apprendere un altro linguaggio per lavorare con il nucleo di database distribuito e fortemente coerente.
In questo articolo abbiamo esplorato come i principi di progettazione dei database differiscano in PostgreSQL, Cassandra e MongoDB. Negli articoli successivi ci tufferemo in concetti avanzati di progettazione come indici, transazioni, JOIN, direttive TTL e documenti JSON.
Vi auguriamo un ottimo fine settimana e vi invitiamo a , che si terrà il 14 maggio.
Fonte: habr.com
