Osnove načrtovanja baze podatkov – primerjava PostgreSQL, Cassandra in MongoDB

Pozdravljeni prijatelji. Pred odhodom na drugi del majskih počitnic z vami delimo gradivo, ki smo ga prevedli v pričakovanju začetka novega toka na tečaju "Relacijska DBMS".

Osnove načrtovanja baze podatkov – primerjava PostgreSQL, Cassandra in MongoDB

Razvijalci aplikacij porabijo veliko časa za primerjavo več operativnih baz podatkov, da bi izbrali tisto, ki najbolj ustreza predvideni delovni obremenitvi. Potrebe lahko vključujejo poenostavljeno modeliranje podatkov, transakcijske garancije, zmogljivost branja/pisanja, horizontalno skaliranje in toleranco napak. Tradicionalno se izbira začne s kategorijo baze podatkov, SQL ali NoSQL, saj vsaka kategorija predstavlja jasen nabor kompromisov. Visoka zmogljivost v smislu nizke zakasnitve in visoke prepustnosti se na splošno obravnava kot zahteva brez kompromisov in je zato bistvena za vsako vzorčno bazo podatkov.

Namen tega članka je pomagati razvijalcem aplikacij narediti pravo izbiro med SQL in NoSQL v kontekstu modeliranja aplikacijskih podatkov. Ogledali si bomo eno bazo podatkov SQL, in sicer PostgreSQL, in dve bazi podatkov NoSQL, Cassandra in MongoDB, da pokrijemo osnove oblikovanja baz podatkov, kot je ustvarjanje tabel, njihovo polnjenje, branje podatkov iz tabele in njihovo brisanje. V naslednjem članku si bomo zagotovo ogledali indekse, transakcije, JOIN-je, direktive TTL in zasnovo baze podatkov, ki temelji na JSON.

Kakšna je razlika med SQL in NoSQL?

Podatkovne baze SQL povečujejo prilagodljivost aplikacij prek transakcijskih jamstev ACID, pa tudi njihove zmožnosti poizvedovanja po podatkih z uporabo JOIN na nepričakovane načine poleg obstoječih normaliziranih modelov relacijskih baz podatkov.

Glede na njihovo monolitno arhitekturo/arhitekturo z enim vozliščem in uporabo modela replikacije glavni-podrejeni za redundanco tradicionalnim bazam podatkov SQL manjka dve pomembni lastnosti – linearna skalabilnost pisanja (tj. samodejno razdeljevanje na več vozlišč) in samodejna/ničelna izguba podatkov. To pomeni, da količina prejetih podatkov ne more preseči največje prepustnosti pisanja posameznega vozlišča. Poleg tega je treba pri toleranci napak upoštevati nekaj začasnih izgub podatkov (v arhitekturi brez skupne rabe). Pri tem morate upoštevati, da nedavne objave še niso bile odražene v podrejeni kopiji. Posodobitve brez izpadov je tudi težko doseči v bazah podatkov SQL.

Baze podatkov NoSQL so običajno porazdeljene po naravi, tj. v njih so podatki razdeljeni na odseke in razporejeni po več vozliščih. Zahtevajo denormalizacijo. To pomeni, da je treba vnesene podatke tudi večkrat kopirati, da odgovorijo na vaše posebne zahteve. Splošni cilj je doseči visoko zmogljivost z zmanjšanjem števila drobcev, ki so na voljo med branjem. To pomeni, da NoSQL zahteva modeliranje vaših poizvedb, medtem ko SQL zahteva modeliranje podatkov.

NoSQL se osredotoča na doseganje visoke zmogljivosti v porazdeljeni gruči in to je temeljna utemeljitev za številne kompromise pri načrtovanju baze podatkov, ki vključujejo izgubo transakcije ACID, JOIN in dosledne globalne sekundarne indekse.

Obstaja argument, da medtem ko baze podatkov NoSQL zagotavljajo linearno razširljivost pisanja in visoko toleranco napak, so zaradi izgube transakcijskih jamstev neprimerne za kritične podatke.

Naslednja tabela prikazuje, kako se modeliranje podatkov v NoSQL razlikuje od SQL.

Osnove načrtovanja baze podatkov – primerjava PostgreSQL, Cassandra in MongoDB

SQL in NoSQL: zakaj sta potrebna oba?

Realne aplikacije z velikim številom uporabnikov, kot so Amazon.com, Netflix, Uber in Airbnb, so zadolžene za izvajanje kompleksnih, večplastnih nalog. Na primer, aplikacija za e-trgovino, kot je Amazon.com, mora shraniti lahke, zelo kritične podatke, kot so informacije o uporabnikih, izdelki, naročila, računi, skupaj s težkimi, manj občutljivimi podatki, kot so ocene izdelkov, sporočila podpore, dejavnost uporabnikov, ocene in priporočila uporabnikov. Seveda se te aplikacije zanašajo na vsaj eno bazo podatkov SQL skupaj z vsaj eno bazo podatkov NoSQL. V medregionalnih in globalnih sistemih baza podatkov NoSQL deluje kot geografsko porazdeljen predpomnilnik za podatke, shranjene v zaupanja vredni izvorni bazi podatkov SQL, ki se izvaja v eni sami regiji.

Kako YugaByte DB združuje SQL in NoSQL?

YugaByte DB, zgrajena na log-orientiranem mešanem mehanizmu za shranjevanje, samodejnem razčlenjevanju, razdrobljeni porazdeljeni konsenzni replikaciji in porazdeljenih transakcijah ACID (navdih Google Spanner), je prva odprtokodna baza podatkov na svetu, ki je hkrati združljiva z NoSQL (Cassandra & Redis) in SQL (PostgreSQL). Kot je prikazano v spodnji tabeli, YCQL, YugaByte DB API, združljiv s Cassandro, dodaja koncepte transakcij ACID z enim ključem in več ključev ter globalnih sekundarnih indeksov v NoSQL API, s čimer uvaja dobo transakcijskih baz podatkov NoSQL. Poleg tega YCQL, YugaByte DB API, združljiv s PostgreSQL, dodaja koncepte linearnega skaliranja pisanja in samodejne tolerance napak v SQL API, s čimer svetu prinaša porazdeljene baze podatkov SQL. Ker je YugaByte DB transakcijske narave, je NoSQL API zdaj mogoče uporabiti v kontekstu kritičnih podatkov.

Osnove načrtovanja baze podatkov – primerjava PostgreSQL, Cassandra in MongoDB

Kot je bilo že navedeno v članku "Predstavljamo YSQL: PostgreSQL združljiv distribuirani SQL API za YugaByte DB", je izbira med SQL ali NoSQL v YugaByte DB popolnoma odvisna od značilnosti osnovne delovne obremenitve:

  • Če so vaša primarna delovna obremenitev operacije JOIN z več ključi, potem pri izbiri YSQL upoštevajte, da so lahko vaši ključi porazdeljeni po več vozliščih, kar povzroči večjo zakasnitev in/ali nižjo prepustnost kot NoSQL.
  • V nasprotnem primeru izberite katerega koli od dveh API-jev NoSQL, pri čemer ne pozabite, da boste dosegli boljšo zmogljivost kot rezultat poizvedb, poslanih iz enega vozlišča naenkrat. YugaByte DB lahko služi kot enotna operativna zbirka podatkov za kompleksne aplikacije v resničnem svetu, ki morajo upravljati več delovnih obremenitev hkrati.

Laboratorij za modeliranje podatkov v naslednjem razdelku temelji na bazah podatkov YugaByte DB, ki so združljive s PostgreSQL in Cassandra API, v nasprotju z izvornimi bazami podatkov. Ta pristop poudarja enostavnost interakcije z dvema različnima API-jema (na dveh različnih vratih) iste gruče baze podatkov, v nasprotju z uporabo popolnoma neodvisnih gruč dveh različnih baz podatkov.
V naslednjih razdelkih si bomo ogledali laboratorij za modeliranje podatkov, da bi ponazorili razlike in nekatere skupne značilnosti obravnavanih baz podatkov.

Laboratorij za modeliranje podatkov

Namestitev baze podatkov

Glede na poudarek na zasnovi podatkovnega modela (namesto na zapletenih arhitekturah uvajanja) bomo baze podatkov namestili v vsebnike Docker na lokalnem računalniku in nato z njimi sodelovali z uporabo njihovih lupin ukazne vrstice.

Baza podatkov YugaByte DB, združljiva s 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_postgres

MongoDB

docker run --name my-mongo -d mongo:latest

Dostop do ukazne vrstice

Povežimo se z bazami podatkov s pomočjo lupine ukazne vrstice za ustrezne API-je.

PostgreSQL

psql je lupina ukazne vrstice za interakcijo s PostgreSQL. Za lažjo uporabo ima YugaByte DB psql neposredno v mapi bin.

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

Cassandra

cqlsh je lupina ukazne vrstice za interakcijo s Cassandro in njenimi združljivimi zbirkami podatkov prek CQL (Cassandra Query Language). Za lažjo uporabo je priložen YugaByte DB cqlsh v katalogu bin.
Upoštevajte, da je CQL navdihnil SQL in ima podobne koncepte tabel, vrstic, stolpcev in indeksov. Vendar pa kot jezik NoSQL dodaja določen nabor omejitev, ki jih bomo večino obravnavali tudi v drugih člankih.

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

MongoDB

mongo je lupina ukazne vrstice za interakcijo z MongoDB. Najdete ga v imeniku bin namestitve MongoDB.

docker exec -it my-mongo bash 
cd bin
mongo

Ustvari tabelo

Zdaj lahko komuniciramo z bazo podatkov za izvajanje različnih operacij z ukazno vrstico. Začnimo z ustvarjanjem tabele, ki hrani informacije o pesmih, ki so jih napisali različni izvajalci. Te pesmi so lahko del albuma. Tudi neobvezni atributi za skladbo so leto izdaje, cena, žanr in ocena. Upoštevati moramo dodatne atribute, ki bodo morda potrebni v prihodnosti prek polja »oznake«. Lahko shrani polstrukturirane podatke v obliki parov ključ-vrednost.

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

Ustvarjanje tabele v Cassandri je zelo podobno PostgreSQL. Ena od glavnih razlik je pomanjkanje omejitev celovitosti (npr. NOT NULL), vendar je to odgovornost aplikacije, ne baze podatkov NoSQL. Primarni ključ je sestavljen iz particijskega ključa (stolpec Izvajalec v spodnjem primeru) in niza stolpcev za združevanje (stolpec SongTitle v spodnjem primeru). Particijski ključ določa, v katero particijo/odrezek naj bo postavljena vrstica, stolpci za združevanje v gruče pa kažejo, kako naj bodo podatki organizirani znotraj trenutnega odseka.

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 organizira podatke v zbirke podatkov (Database) (podobno kot Keyspace v Cassandri), kjer so zbirke (podobno kot tabele), ki vsebujejo dokumente (podobno kot vrstice v tabeli). V MongoDB načeloma ni potrebe po definiranju začetne sheme. Ekipa "uporabi bazo podatkov", prikazan spodaj, instancira bazo podatkov ob prvem klicu in spremeni kontekst za novo ustvarjeno bazo podatkov. Tudi zbirk ni treba izrecno ustvariti; ustvarjene so samodejno, preprosto ko dodate prvi dokument v novo zbirko. Upoštevajte, da MongoDB privzeto uporablja preskusno bazo podatkov, tako da se bo vsaka operacija na ravni zbirke, ne da bi podali določeno bazo podatkov, privzeto izvajala na njej.

use myNewDatabase;

Pridobivanje informacij o tabeli
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;

Vnos podatkov v tabelo
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

Celoten izraz INSERT v Cassandri je zelo podoben tistemu v PostgreSQL. Vendar pa obstaja ena velika razlika v semantiki. V Kasandri INSERT je pravzaprav operacija UPSERT, kjer se vrstici dodajo zadnje vrednosti, če vrstica že obstaja.

Vnos podatkov je podoben PostgreSQL INSERT zgoraj

.

MongoDB

Čeprav je MongoDB baza podatkov NoSQL, kot je Cassandra, njena operacija vstavljanja nima nič skupnega s semantičnim obnašanjem Cassandre. V MongoDB vstavi() nima možnosti UPSERT, zaradi česar je podoben PostgreSQL. Dodajanje privzetih podatkov brez _idspecified bo povzročilo, da bo v zbirko dodan nov dokument.

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"
}
}
);

Poizvedba tabele

Morda je najpomembnejša razlika med SQL in NoSQL v smislu konstrukcije poizvedbe uporabljeni jezik FROM и WHERE. SQL omogoča po izrazu FROM izberite več tabel in izraz z WHERE je lahko poljubne zapletenosti (vključno z operacijami JOIN med mizami). Vendar pa NoSQL nalaga stroge omejitve FROMin delajte samo z eno določeno tabelo in v WHERE, mora biti vedno naveden primarni ključ. To je povezano s pospeševanjem zmogljivosti NoSQL, o katerem smo govorili prej. Ta želja vodi do vsega možnega zmanjšanja kakršne koli medtabelarne in medključne interakcije. Pri odzivanju na zahtevo lahko povzroči veliko zamudo pri komunikaciji med vozlišči, zato se ji je na splošno najbolje izogniti. Na primer, Cassandra zahteva, da so poizvedbe omejene na določene operaterje (samo =, IN, <, >, =>, <=) na particijskih ključih, razen ko zahtevate sekundarni indeks (tu je dovoljen samo operator =).

PostgreSQL

Spodaj so trije primeri poizvedb, ki jih lahko enostavno izvede baza podatkov SQL.

  • Prikažite vse pesmi izvajalca;
  • Prikažite vse pesmi izvajalca, ki se ujemajo s prvim delom naslova;
  • Prikažite vse pesmi izvajalca, ki imajo določeno besedo v naslovu in imajo ceno nižjo od 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

Od zgoraj naštetih poizvedb PostgreSQL bo samo prva v Cassandri delovala nespremenjeno, saj operater LIKE ni mogoče uporabiti za združevanje stolpcev, kot je npr SongTitle. V tem primeru so dovoljeni samo operaterji = и 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

Kot je prikazano v prejšnjih primerih, je glavna metoda za ustvarjanje poizvedb v MongoDB db.collection.find(). Ta metoda izrecno vsebuje ime zbirke (music v spodnjem primeru), zato je poizvedovanje po več zbirkah prepovedano.

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

Branje vseh vrstic tabele

Branje vseh vrstic je preprosto poseben primer vzorca poizvedbe, ki smo si ga ogledali prej.

PostgreSQL

SELECT * 
FROM Music;

Cassandra

Podobno zgornjemu primeru PostgreSQL.

MongoDB

db.music.find( {} );

Urejanje podatkov v tabeli

PostgreSQL

PostgreSQL ponuja navodila UPDATE za spremembo podatkov. Nima priložnosti UPSERT, zato ta stavek ne bo uspel, če vrstice ni več v bazi podatkov.

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

Cassandra

Cassandra ima UPDATE podobno kot PostgreSQL. UPDATE ima enako semantiko UPSERT, podobno INSERT.

Podobno zgornjemu primeru PostgreSQL.

MongoDB
Operacija nadgradnja() v MongoDB lahko v celoti posodobi obstoječi dokument ali posodobi samo določena polja. Privzeto posodobi samo en dokument z onemogočeno semantiko UPSERT. Posodabljanje več dokumentov in podobno vedenje UPSERT lahko uporabite z nastavitvijo dodatnih zastavic za operacijo. Na primer, v spodnjem primeru se žanr določenega izvajalca posodobi glede na njegovo pesem.

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

Odstranjevanje podatkov iz tabele

PostgreSQL

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

Cassandra

Podobno zgornjemu primeru PostgreSQL.

MongoDB

MongoDB ima dve vrsti operacij za brisanje dokumentov − deleteOne() /deleteMany() и Odstrani(). Obe vrsti izbrišeta dokumente, vendar vrneta različne rezultate.

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

Brisanje tabele

PostgreSQL

DROP TABLE Music;

Cassandra

Podobno zgornjemu primeru PostgreSQL.

MongoDB

db.music.drop();

Zaključek

Razprava o izbiri med SQL in NoSQL divja že več kot 10 let. Obstajata dva glavna vidika te razprave: arhitektura mehanizma baze podatkov (monolitni, transakcijski SQL v primerjavi s porazdeljenim, netransakcijskim NoSQL) in pristop oblikovanja baze podatkov (modeliranje vaših podatkov v SQL v primerjavi z modeliranjem vaših poizvedb v NoSQL).

S porazdeljeno transakcijsko zbirko podatkov, kot je YugaByte DB, je mogoče razpravo o arhitekturi baze podatkov enostavno končati. Ko količine podatkov postanejo večje od tistih, ki jih je mogoče zapisati v posamezno vozlišče, postane potrebna popolnoma porazdeljena arhitektura, ki podpira linearno razširljivost pisanja s samodejnim razdeljevanjem/ponovnim uravnoteženjem.

Poleg tega, kot je navedeno v enem od člankov Google CloudTransakcijske, močno konsistentne arhitekture se zdaj bolj uporabljajo za zagotavljanje boljše razvojne agilnosti kot netransakcijske, sčasoma konsistentne arhitekture.

Če se vrnemo k razpravi o oblikovanju baze podatkov, je pošteno reči, da sta oba pristopa oblikovanja (SQL in NoSQL) potrebna za vsako kompleksno aplikacijo v resničnem svetu. Pristop "modeliranja podatkov" SQL omogoča razvijalcem, da lažje izpolnjujejo spreminjajoče se poslovne zahteve, medtem ko pristop "modeliranja poizvedb" NoSQL omogoča istim razvijalcem, da delujejo na velikih količinah podatkov z nizko zakasnitvijo in visoko prepustnostjo. Zaradi tega YugaByte DB ponuja API-je SQL in NoSQL v skupnem jedru, namesto da bi promoviral enega od pristopov. Poleg tega YugaByte DB z zagotavljanjem združljivosti s priljubljenimi jeziki podatkovnih baz, vključno s PostgreSQL in Cassandra, zagotavlja, da razvijalcem ni treba učiti drugega jezika za delo s porazdeljenim, zelo konsistentnim mehanizmom baze podatkov.

V tem članku smo pogledali, kako se osnove zasnove baze podatkov razlikujejo med PostgreSQL, Cassandro in MongoDB. V prihodnjih člankih se bomo poglobili v napredne koncepte oblikovanja, kot so indeksi, transakcije, JOIN-ji, direktive TTL in dokumenti JSON.

Želimo vam lep preostanek vikenda in vas vabimo brezplačni spletni seminar, ki bo 14. maja.

Vir: www.habr.com

Dodaj komentar