Bună prieteni. Înainte de a pleca în a doua parte a sărbătorilor de mai, vă împărtășim materialul pe care l-am tradus în așteptarea lansării unui nou flux pe curs
Dezvoltatorii de aplicații petrec mult timp comparând mai multe baze de date operaționale pentru a o selecta pe cea care se potrivește cel mai bine volumului de lucru prevăzut. Nevoile pot include modelarea simplificată a datelor, garanții tranzacționale, performanță de citire/scriere, scalare orizontală și toleranță la erori. În mod tradițional, alegerea începe cu categoria bazei de date, SQL sau NoSQL, deoarece fiecare categorie prezintă un set clar de compromisuri. Performanța înaltă în ceea ce privește latența scăzută și debitul mare este în general văzută ca o cerință fără compromis și, prin urmare, este esențială pentru orice bază de date eșantion.
Scopul acestui articol este de a ajuta dezvoltatorii de aplicații să facă alegerea corectă între SQL și NoSQL în contextul modelării datelor aplicației. Vom analiza o bază de date SQL, și anume PostgreSQL, și două baze de date NoSQL, Cassandra și MongoDB, pentru a acoperi elementele de bază ale designului bazei de date, cum ar fi crearea de tabele, popularea acestora, citirea datelor dintr-un tabel și ștergerea acestuia. În următorul articol, ne vom asigura că ne uităm la indici, tranzacții, JOIN-uri, directive TTL și design de baze de date bazat pe JSON.
Care este diferența dintre SQL și NoSQL?
Bazele de date SQL măresc flexibilitatea aplicațiilor prin garanțiile tranzacționale ACID, precum și capacitatea lor de a interoga datele folosind JOIN-uri în moduri neașteptate, pe lângă modelele de baze de date relaționale existente.
Având în vedere arhitectura lor monolitică/cu un singur nod și utilizarea unui model de replicare master-slave pentru redundanță, bazele de date tradiționale SQL nu au două caracteristici importante - scalabilitatea liniară a scrierii (adică partiționarea automată pe mai multe noduri) și pierderea automată/zero de date. Aceasta înseamnă că cantitatea de date primite nu poate depăși viteza maximă de scriere a unui singur nod. În plus, unele pierderi temporare de date trebuie luate în considerare în toleranța la erori (într-o arhitectură shared-nothing). Aici trebuie să rețineți că comiterile recente nu au fost încă reflectate în copia slave. Actualizările non-time sunt, de asemenea, dificil de realizat în bazele de date SQL.
Bazele de date NoSQL sunt de obicei distribuite prin natură, adică. în ele, datele sunt împărțite în secțiuni și distribuite pe mai multe noduri. Ele necesită denormalizare. Aceasta înseamnă că datele introduse trebuie și ele copiate de mai multe ori pentru a răspunde solicitărilor specifice pe care le trimiteți. Scopul general este de a obține performanțe ridicate prin reducerea numărului de fragmente disponibile în timpul citirilor. Acest lucru implică faptul că NoSQL vă cere să vă modelați interogările, în timp ce SQL vă cere să vă modelați datele.
NoSQL se concentrează pe obținerea de performanțe ridicate într-un cluster distribuit și acesta este rațiunea de bază pentru multe compromisuri de proiectare a bazelor de date care includ pierderea tranzacțiilor ACID, JOIN-uri și indici secundari globali consecvenți.
Există un argument că, în timp ce bazele de date NoSQL oferă scalabilitate liniară de scriere și toleranță ridicată la erori, pierderea garanțiilor tranzacționale le face nepotrivite pentru datele esențiale.
Următorul tabel arată modul în care modelarea datelor în NoSQL diferă de SQL.
SQL și NoSQL: de ce sunt necesare ambele?
Aplicațiile din lumea reală cu un număr mare de utilizatori, cum ar fi Amazon.com, Netflix, Uber și Airbnb, au sarcina de a efectua sarcini complexe, cu mai multe fațete. De exemplu, o aplicație de comerț electronic precum Amazon.com trebuie să stocheze date ușoare, extrem de critice, cum ar fi informații despre utilizatori, produse, comenzi, facturi, împreună cu date grele și mai puțin sensibile, cum ar fi recenzii despre produse, mesaje de asistență, activitatea utilizatorului, recenzii și recomandări ale utilizatorilor. Desigur, aceste aplicații se bazează pe cel puțin o bază de date SQL împreună cu cel puțin o bază de date NoSQL. În sistemele interregionale și globale, o bază de date NoSQL funcționează ca un cache geo-distribuit pentru datele stocate într-o bază de date SQL sursă de încredere care rulează într-o singură regiune.
Cum combina YugaByte DB SQL și NoSQL?
Construit pe un motor de stocare mixt orientat spre jurnal, auto-sharding, replicare sharded distribuită consens și tranzacții distribuite ACID (inspirat de Google Spanner), YugaByte DB este prima bază de date open source din lume care este simultan compatibilă cu NoSQL (Cassandra & Redis) și SQL (PostgreSQL). După cum se arată în tabelul de mai jos, YCQL, YugaByte DB API compatibil cu Cassandra, adaugă conceptele de tranzacții ACID cu o singură cheie și mai multe chei și indici secundari globali la API-ul NoSQL, inaugurând astfel era bazelor de date tranzacționale NoSQL. În plus, YCQL, YugaByte DB API compatibil cu PostgreSQL, adaugă conceptele de scalare liniară a scrierii și toleranță automată la erori la API-ul SQL, aducând bazele de date SQL distribuite în lume. Deoarece YugaByte DB este de natură tranzacțională, API-ul NoSQL poate fi utilizat acum în contextul datelor critice pentru misiune.
După cum s-a menționat anterior în articol
- Dacă sarcina dvs. principală de lucru este operațiunile JOIN cu mai multe chei, atunci când alegeți YSQL, înțelegeți că cheile dvs. pot fi distribuite pe mai multe noduri, ceea ce duce la o latență mai mare și/sau un debit mai mic decât NoSQL.
- În caz contrar, alegeți oricare dintre cele două API-uri NoSQL, ținând cont că veți obține performanțe mai bune ca urmare a interogărilor servite de la un nod la un moment dat. YugaByte DB poate servi ca o bază de date operațională unică pentru aplicații complexe din lumea reală care trebuie să gestioneze mai multe sarcini de lucru simultan.
Laboratorul de modelare a datelor din secțiunea următoare se bazează pe baze de date YugaByte DB compatibile cu PostgreSQL și Cassandra API, spre deosebire de bazele de date native. Această abordare subliniază ușurința interacțiunii cu două API-uri diferite (pe două porturi diferite) ale aceluiași cluster de baze de date, spre deosebire de utilizarea clusterelor complet independente a două baze de date diferite.
În secțiunile următoare, vom arunca o privire asupra laboratorului de modelare a datelor pentru a ilustra diferențele și unele dintre punctele comune ale bazelor de date acoperite.
Laborator de modelare a datelor
Instalarea bazei de date
Având în vedere accentul pus pe proiectarea modelului de date (mai degrabă decât arhitecturi complexe de implementare), vom instala baze de date în containere Docker pe mașina locală și apoi vom interacționa cu acestea folosind shell-urile de linie de comandă respective.
Baza de date YugaByte DB compatibilă PostgreSQL și 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
Acces la linia de comandă
Să ne conectăm la bazele de date folosind shell-ul liniei de comandă pentru API-urile corespunzătoare.
PostgreSQL
docker exec -it yb-postgres-n1 /home/yugabyte/postgres/bin/psql -p 5433 -U postgres
Cassandra
cqlsh
în catalog bin
.
Rețineți că CQL a fost inspirat de SQL și are concepte similare de tabele, rânduri, coloane și indici. Cu toate acestea, ca limbaj NoSQL, adaugă un anumit set de limitări, dintre care majoritatea le vom acoperi și în alte articole.
docker exec -it yb-tserver-n1 /home/yugabyte/bin/cqlsh
MongoDB
docker exec -it my-mongo bash
cd bin
mongo
Creați un tabel
Acum putem interacționa cu baza de date pentru a efectua diverse operații folosind linia de comandă. Să începem prin a crea un tabel care stochează informații despre melodiile scrise de diferiți artiști. Aceste melodii pot face parte dintr-un album. De asemenea, atributele opționale pentru o melodie sunt anul lansării, prețul, genul și ratingul. Trebuie să luăm în considerare atributele suplimentare care ar putea fi necesare în viitor prin câmpul „etichete”. Poate stoca date semi-structurate sub formă de perechi cheie-valoare.
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
Crearea unui tabel în Cassandra este foarte asemănătoare cu PostgreSQL. Una dintre principalele diferențe este lipsa constrângerilor de integritate (de exemplu, NOT NULL), dar aceasta este responsabilitatea aplicației, nu a bazei de date NoSQL.. Cheia primară constă dintr-o cheie de partiție (coloana Artist din exemplul de mai jos) și un set de coloane de grupare (coloana SongTitle din exemplul de mai jos). Cheia de partiție determină în ce partiție/shard trebuie plasat rândul, iar coloanele de grupare indică modul în care datele ar trebui să fie organizate în fragmentul curent.
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 organizează datele în baze de date (Baza de date) (similar cu Keyspace în Cassandra), unde există Colecții (asemănătoare cu tabelele) care conțin Documente (asemănătoare cu rândurile dintr-un tabel). În MongoDB, practic nu este nevoie să definiți o schemă inițială. Echipă "utilizați baza de date", prezentat mai jos, instanțiază baza de date la primul apel și modifică contextul pentru noua bază de date creată. Nici măcar colecțiile nu trebuie să fie create în mod explicit; ele sunt create automat, pur și simplu când adăugați primul document la o nouă colecție. Rețineți că MongoDB folosește baza de date de testare în mod implicit, astfel încât orice operațiune la nivel de colecție fără a specifica o anumită bază de date va rula în mod implicit pe ea.
use myNewDatabase;
Obținerea de informații despre un tabel
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;
Introducerea datelor într-un tabel
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
Expresie generală INSERT
în Cassandra arată foarte asemănător cu cel din PostgreSQL. Cu toate acestea, există o mare diferență în semantică. În Cassandra INSERT
este de fapt o operațiune UPSERT
, unde ultimele valori sunt adăugate la rând dacă rândul există deja.
Introducerea datelor este similară cu PostgreSQL
INSERT
mai sus
.
MongoDB
Chiar dacă MongoDB este o bază de date NoSQL ca Cassandra, operația sa de inserare nu are nimic în comun cu comportamentul semantic al lui Cassandra. În MongoDB UPSERT
, ceea ce îl face similar cu PostgreSQL. Adăugarea datelor implicite fără _idspecified
va face ca un nou document să fie adăugat la colecție.
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"
}
}
);
Interogare la tabel
Poate cea mai semnificativă diferență dintre SQL și NoSQL în ceea ce privește construcția interogărilor este limbajul folosit FROM
и WHERE
. SQL permite după exprimare FROM
selectează mai multe tabele și expresie cu WHERE
poate fi de orice complexitate (inclusiv operațiuni JOIN
între mese). Cu toate acestea, NoSQL tinde să impună o limitare severă asupra FROM
, și lucrează numai cu un tabel specificat și în WHERE
, cheia primară trebuie întotdeauna specificată. Acest lucru se leagă de impulsul de performanță NoSQL despre care am vorbit mai devreme. Această dorință duce la orice reducere posibilă a oricărei interacțiuni încrucișate și încrucișate. Poate introduce o întârziere mare în comunicarea între noduri atunci când răspunde la o solicitare și, prin urmare, este cel mai bine evitată în general. De exemplu, Cassandra cere ca interogările să fie limitate la anumiți operatori (numai =, IN, <, >, =>, <=
) pe cheile de partiție, cu excepția interogării unui index secundar (numai operatorul = este permis aici).
PostgreSQL
Mai jos sunt trei exemple de interogări care pot fi executate cu ușurință de o bază de date SQL.
- Afișează toate melodiile unui artist;
- Afișează toate melodiile artistului care se potrivesc cu prima parte a titlului;
- Afișează toate melodiile unui artist care au un anumit cuvânt în titlu și au un preț mai mic de 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
Dintre interogările PostgreSQL enumerate mai sus, doar prima va funcționa neschimbată în Cassandra, deoarece operatorul LIKE
nu poate fi aplicat la gruparea coloanelor, cum ar fi SongTitle
. În acest caz, sunt permise numai operatorii =
и 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
După cum se arată în exemplele anterioare, metoda principală pentru crearea de interogări în MongoDB este music
în exemplul de mai jos), deci interogarea mai multor colecții este interzisă.
db.music.find( {
artist: "No One You Know"
}
);
db.music.find( {
artist: "No One You Know",
songTitle: /Call/
}
);
Citirea tuturor rândurilor unui tabel
Citirea tuturor rândurilor este pur și simplu un caz special al modelului de interogare la care ne-am uitat mai devreme.
PostgreSQL
SELECT *
FROM Music;
Cassandra
Similar cu exemplul PostgreSQL de mai sus.
MongoDB
db.music.find( {} );
Editarea datelor într-un tabel
PostgreSQL
PostgreSQL oferă instrucțiuni UPDATE
pentru a schimba datele. Ea nu are oportunități UPSERT
, deci această declarație va eșua dacă rândul nu se mai află în baza de date.
UPDATE Music
SET Genre = 'Disco'
WHERE Artist = 'The Acme Band' AND SongTitle = 'Still In Love';
Cassandra
Cassandra are UPDATE
similar cu PostgreSQL. UPDATE
are aceeași semantică UPSERT
, asemănător INSERT
.
Similar cu exemplul PostgreSQL de mai sus.
MongoDB
Operație UPSERT
. Actualizarea mai multor documente și comportament similar UPSERT
poate fi aplicat prin setarea de steaguri suplimentare pentru operație. De exemplu, în exemplul de mai jos, genul unui anumit artist este actualizat în funcție de cântecul său.
db.music.update(
{"artist": "The Acme Band"},
{
$set: {
"genre": "Disco"
}
},
{"multi": true, "upsert": true}
);
Eliminarea datelor dintr-un tabel
PostgreSQL
DELETE FROM Music
WHERE Artist = 'The Acme Band' AND SongTitle = 'Look Out, World';
Cassandra
Similar cu exemplul PostgreSQL de mai sus.
MongoDB
MongoDB are două tipuri de operații pentru ștergerea documentelor −
db.music.deleteMany( {
artist: "The Acme Band"
}
);
Ștergerea unui tabel
PostgreSQL
DROP TABLE Music;
Cassandra
Similar cu exemplul PostgreSQL de mai sus.
MongoDB
db.music.drop();
Concluzie
Dezbaterea despre alegerea între SQL și NoSQL face furori de mai bine de 10 ani. Există două aspecte principale ale acestei dezbateri: arhitectura motorului de baze de date (monolitic, SQL tranzacțional vs distribuit, NoSQL non-tranzacțional) și abordarea de proiectare a bazei de date (modelarea datelor în SQL vs modelarea interogărilor în NoSQL).
Cu o bază de date tranzacțională distribuită precum YugaByte DB, dezbaterea despre arhitectura bazei de date poate fi ușor oprită. Pe măsură ce volumele de date devin mai mari decât ceea ce poate fi scris pe un singur nod, devine necesară o arhitectură complet distribuită care să accepte scalabilitate liniară de scriere cu fragmentare/reechilibrare automată.
În plus, așa cum se spune într-unul dintre articole
Revenind la discuția despre proiectarea bazei de date, este corect să spunem că ambele abordări de proiectare (SQL și NoSQL) sunt necesare pentru orice aplicație complexă din lumea reală. Abordarea de „modelare a datelor” SQL permite dezvoltatorilor să îndeplinească mai ușor cerințele de afaceri în schimbare, în timp ce abordarea de „modelare a interogărilor” NoSQL permite acelorași dezvoltatori să opereze pe volume mari de date cu latență scăzută și debit mare. Din acest motiv, YugaByte DB oferă API-uri SQL și NoSQL într-un nucleu comun, mai degrabă decât să promoveze una dintre abordări. În plus, oferind compatibilitate cu limbaje populare de baze de date, inclusiv PostgreSQL și Cassandra, YugaByte DB se asigură că dezvoltatorii nu trebuie să învețe o altă limbă pentru a lucra cu un motor de baze de date distribuit, foarte consistent.
În acest articol, am analizat cum diferă elementele fundamentale ale designului bazei de date între PostgreSQL, Cassandra și MongoDB. În articolele viitoare, ne vom scufunda în concepte avansate de design, cum ar fi indici, tranzacții, JOIN-uri, directive TTL și documente JSON.
Vă dorim un rest minunat de weekend și vă invităm
Sursa: www.habr.com