Osnove dizajna baze podataka - usporedba PostgreSQL-a, Cassandre i MongoDB-a

Pozdrav prijatelji. Prije odlaska na drugi dio svibanjskih praznika, s vama dijelimo materijal koji smo preveli u očekivanju pokretanja novog streama na tečaju "Relacijski DBMS".

Osnove dizajna baze podataka - usporedba PostgreSQL-a, Cassandre i MongoDB-a

Programeri aplikacija provode mnogo vremena uspoređujući više operativnih baza podataka kako bi odabrali onu koja najbolje odgovara planiranom radnom opterećenju. Potrebe mogu uključivati ​​pojednostavljeno modeliranje podataka, transakcijska jamstva, performanse čitanja/pisanja, horizontalno skaliranje i toleranciju na pogreške. Tradicionalno, izbor počinje kategorijom baze podataka, SQL ili NoSQL, budući da svaka kategorija predstavlja jasan skup kompromisa. Visoka izvedba u smislu niske latencije i velike propusnosti općenito se smatra zahtjevom bez kompromisa i stoga je ključna za svaku oglednu bazu podataka.

Svrha ovog članka je pomoći programerima aplikacija da naprave pravi izbor između SQL-a i NoSQL-a u kontekstu modeliranja podataka aplikacije. Pogledat ćemo jednu SQL bazu podataka, naime PostgreSQL, i dvije NoSQL baze podataka, Cassandra i MongoDB, kako bismo pokrili osnove dizajna baze podataka, kao što je stvaranje tablica, njihovo popunjavanje, čitanje podataka iz tablice i njihovo brisanje. U sljedećem članku sigurno ćemo pogledati indekse, transakcije, JOIN-ove, TTL direktive i dizajn baze podataka temeljen na JSON-u.

Koja je razlika između SQL-a i NoSQL-a?

SQL baze podataka povećavaju fleksibilnost aplikacija kroz ACID transakcijska jamstva, kao i njihovu sposobnost postavljanja upita podacima pomoću JOIN-ova na neočekivane načine povrh postojećih normaliziranih modela relacijskih baza podataka.

S obzirom na njihovu monolitnu arhitekturu/arhitekturu s jednim čvorom i korištenje modela replikacije master-slave za redundantnost, tradicionalnim SQL bazama podataka nedostaju dvije važne značajke - skalabilnost linearnog pisanja (tj. automatska particija na više čvorova) i automatski/nulti gubitak podataka. To znači da količina primljenih podataka ne može premašiti maksimalnu propusnost pisanja jednog čvora. Osim toga, određeni privremeni gubitak podataka mora se uzeti u obzir u toleranciji grešaka (u arhitekturi bez dijeljenja). Ovdje trebate imati na umu da se nedavna predaja još uvijek nije odrazila na podređenu kopiju. Ažuriranja bez prekida također je teško postići u SQL bazama podataka.

NoSQL baze podataka obično su distribuirane po prirodi, tj. u njima su podaci podijeljeni u sekcije i raspoređeni na nekoliko čvorova. Oni zahtijevaju denormalizaciju. To znači da se uneseni podaci također moraju kopirati nekoliko puta kako bi se odgovorilo na specifične zahtjeve koje šaljete. Opći cilj je postizanje visokih performansi smanjenjem broja dostupnih fragmenata tijekom čitanja. To implicira da NoSQL zahtijeva modeliranje vaših upita, dok SQL zahtijeva modeliranje podataka.

NoSQL se usredotočuje na postizanje visokih performansi u distribuiranom klasteru i to je temeljni razlog za mnoge kompromise dizajna baze podataka koji uključuju ACID gubitak transakcija, JOIN-ove i konzistentne globalne sekundarne indekse.

Postoji argument da dok NoSQL baze podataka pružaju skalabilnost linearnog pisanja i visoku toleranciju na pogreške, gubitak transakcijskih jamstava ih čini neprikladnima za podatke kritične za misiju.

Sljedeća tablica pokazuje kako se modeliranje podataka u NoSQL-u razlikuje od SQL-a.

Osnove dizajna baze podataka - usporedba PostgreSQL-a, Cassandre i MongoDB-a

SQL i NoSQL: Zašto su oba potrebna?

Aplikacije iz stvarnog svijeta s velikim brojem korisnika, kao što su Amazon.com, Netflix, Uber i Airbnb, imaju zadatak obavljati složene, višestruke zadatke. Na primjer, aplikacija za e-trgovinu kao što je Amazon.com treba pohraniti lagane, visoko kritične podatke kao što su informacije o korisniku, proizvodi, narudžbe, fakture, zajedno s teškim, manje osjetljivim podacima kao što su recenzije proizvoda, poruke podrške, aktivnosti korisnika, recenzije i preporuke korisnika. Naravno, te se aplikacije oslanjaju na najmanje jednu SQL bazu podataka zajedno s najmanje jednom NoSQL bazom podataka. U međuregionalnim i globalnim sustavima, NoSQL baza podataka radi kao geo-distribuirana predmemorija za podatke pohranjene u pouzdanoj izvornoj SQL bazi podataka koja se izvodi u određenoj regiji.

Kako YugaByte DB kombinira SQL i NoSQL?

Izgrađen na log-orijentiranom motoru za mješovitu pohranu, automatskom dijeljenju, podijeljenoj distribuiranoj replikaciji konsenzusa i ACID distribuiranim transakcijama (nadahnut Google Spannerom), YugaByte DB je prva baza podataka otvorenog koda na svijetu koja je istovremeno kompatibilna s NoSQL (Cassandra & Redis) i SQL (PostgreSQL). Kao što je prikazano u tablici ispod, YCQL, YugaByte DB API kompatibilan s Cassandrom, dodaje koncepte ACID transakcija s jednim i više ključeva i globalnih sekundarnih indeksa NoSQL API-ju, čime započinje era transakcijskih NoSQL baza podataka. Dodatno, YCQL, YugaByte DB API kompatibilan s PostgreSQL-om, dodaje koncepte skaliranja linearnog pisanja i automatske tolerancije grešaka u SQL API, donoseći svijetu distribuirane SQL baze podataka. Budući da je YugaByte DB transakcijske prirode, NoSQL API sada se može koristiti u kontekstu podataka kritičnih za misiju.

Osnove dizajna baze podataka - usporedba PostgreSQL-a, Cassandre i MongoDB-a

Kao što je prethodno navedeno u članku "Predstavljamo YSQL: PostgreSQL kompatibilan distribuirani SQL API za YugaByte DB", izbor između SQL-a ili NoSQL-a u YugaByte DB-u u potpunosti ovisi o karakteristikama osnovnog radnog opterećenja:

  • Ako su vaše primarno radno opterećenje operacije JOIN s više ključeva, tada pri odabiru YSQL-a imajte na umu da vaši ključevi mogu biti raspodijeljeni na više čvorova, što rezultira većom latencijom i/ili nižom propusnošću od NoSQL-a.
  • U suprotnom odaberite bilo koji od dva NoSQL API-ja, imajući na umu da ćete dobiti bolju izvedbu kao rezultat upita koji se poslužuju s jednog po jednog čvora. YugaByte DB može poslužiti kao jedinstvena operativna baza podataka za složene aplikacije u stvarnom svijetu koje trebaju upravljati višestrukim radnim opterećenjima istovremeno.

Laboratorij za modeliranje podataka u sljedećem odjeljku temelji se na YugaByte DB bazama podataka kompatibilnim s PostgreSQL i Cassandra API-jem, za razliku od izvornih baza podataka. Ovaj pristup naglašava jednostavnost interakcije s dva različita API-ja (na dva različita priključka) istog klastera baze podataka, za razliku od korištenja potpuno neovisnih klastera dviju različitih baza podataka.
U sljedećim odjeljcima pogledat ćemo laboratorij za modeliranje podataka kako bismo ilustrirali razlike i neke zajedničke karakteristike obuhvaćenih baza podataka.

Laboratorij za modeliranje podataka

Instalacija baze podataka

S obzirom na naglasak na dizajnu modela podataka (umjesto složenih arhitektura implementacije), instalirat ćemo baze podataka u Docker spremnike na lokalnom računalu i zatim komunicirati s njima koristeći njihove odgovarajuće ljuske naredbenog retka.

YugaByte DB baza podataka kompatibilna s 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

Pristup naredbenom retku

Povežimo se s bazama podataka pomoću ljuske naredbenog retka za odgovarajuće API-je.

PostgreSQL

psql je ljuska naredbenog retka za interakciju s PostgreSQL-om. Radi lakšeg korištenja, YugaByte DB dolazi s psql-om izravno u mapi bin.

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

Cassandra

cqlsh je ljuska naredbenog retka za interakciju s Cassandrom i njezinim kompatibilnim bazama podataka putem CQL-a (Cassandra Query Language). Radi lakšeg korištenja, YugaByte DB dolazi s cqlsh u katalogu bin.
Imajte na umu da je CQL inspiriran SQL-om i ima slične koncepte tablica, redaka, stupaca i indeksa. Međutim, kao NoSQL jezik, dodaje određeni skup ograničenja, od kojih ćemo većinu također obraditi u drugim člancima.

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

MongoDB

Mongo je ljuska naredbenog retka za interakciju s MongoDB-om. Može se pronaći u direktoriju bin MongoDB instalacije.

docker exec -it my-mongo bash 
cd bin
mongo

Izrada tablice

Sada možemo komunicirati s bazom podataka za izvođenje raznih operacija pomoću naredbenog retka. Započnimo stvaranjem tablice koja pohranjuje informacije o pjesmama koje su napisali različiti izvođači. Ove pjesme mogu biti dio albuma. Također izborni atributi za pjesmu su godina izdanja, cijena, žanr i ocjena. Moramo uzeti u obzir dodatne atribute koji bi mogli biti potrebni u budućnosti kroz polje "oznake". Može pohraniti polustrukturirane podatke u obliku parova ključ-vrijednost.

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

Stvaranje tablice u Cassandri vrlo je slično PostgreSQL-u. Jedna od glavnih razlika je nedostatak ograničenja integriteta (npr. NOT NULL), ali to je odgovornost aplikacije, a ne NoSQL baze podataka. Primarni ključ sastoji se od particijskog ključa (stupac Izvođač u primjeru u nastavku) i skupa stupaca grupiranja (stupac Naslov pjesme u primjeru u nastavku). Ključ particije određuje u koju particiju/shard treba smjestiti red, a stupci klasteriranja pokazuju kako bi podaci trebali biti organizirani unutar trenutnog sharda.

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 u baze podataka (Database) (slično Keyspaceu u Cassandri), gdje postoje Zbirke (slično tablicama) koje sadrže Dokumente (slično redovima u tablici). U MongoDB-u u osnovi nema potrebe za definiranjem početne sheme. Tim "koristi bazu podataka", prikazan dolje, instancira bazu podataka pri prvom pozivu i mijenja kontekst za novostvorenu bazu podataka. Čak ni zbirke ne moraju biti izričito stvorene; one se stvaraju automatski, jednostavno kada dodate prvi dokument u novu zbirku. Imajte na umu da MongoDB koristi testnu bazu podataka prema zadanim postavkama, tako da će se svaka operacija na razini zbirke bez navođenja određene baze podataka izvoditi na njoj prema zadanim postavkama.

use myNewDatabase;

Dobivanje informacija o tablici
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;

Unos podataka u tablicu
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

Ukupni izraz INSERT u Cassandri izgleda vrlo slično onome u PostgreSQL-u. Međutim, postoji jedna velika razlika u semantici. U Kasandri INSERT zapravo je operacija UPSERT, gdje se posljednje vrijednosti dodaju u red ako red već postoji.

Unos podataka sličan je PostgreSQL-u INSERT iznad

.

MongoDB

Iako je MongoDB NoSQL baza podataka poput Cassandre, njezina operacija umetanja nema ništa zajedničko sa semantičkim ponašanjem Cassandre. U MongoDB-u umetnuti() nema mogućnosti UPSERT, što ga čini sličnim PostgreSQL-u. Dodavanje zadanih podataka bez _idspecified uzrokovat će dodavanje novog dokumenta u zbirku.

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

Upit tablice

Možda je najznačajnija razlika između SQL-a i NoSQL-a u smislu konstrukcije upita jezik koji se koristi FROM и WHERE. SQL dopušta naknadni izraz FROM odaberite više tablica i izraz sa WHERE može biti bilo koje složenosti (uključujući operacije JOIN između stolova). Međutim, NoSQL nastoji nametnuti ozbiljna ograničenja FROM, i raditi samo s jednom navedenom tablicom, i in WHERE, uvijek mora biti naveden primarni ključ. Ovo je povezano s povećanjem performansi NoSQL-a o kojem smo ranije govorili. Ova želja dovodi do svakog mogućeg smanjenja bilo koje međutabularne i međuključne interakcije. Može dovesti do velikog kašnjenja u komunikaciji između čvorova prilikom odgovaranja na zahtjev i stoga ga je općenito najbolje izbjegavati. Na primjer, Cassandra zahtijeva da upiti budu ograničeni na određene operatore (samo =, IN, <, >, =>, <=) na ključevima particije, osim kada se traži sekundarni indeks (ovdje je dopušten samo operator =).

PostgreSQL

Ispod su tri primjera upita koje SQL baza podataka može jednostavno izvršiti.

  • Prikaz svih pjesama izvođača;
  • Prikaži sve pjesme izvođača koje odgovaraju prvom dijelu naslova;
  • Prikaz svih pjesama izvođača koje imaju određenu riječ u naslovu i imaju cijenu manju 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 gore navedenih PostgreSQL upita, samo će prvi raditi nepromijenjeno u Cassandri, budući da operator LIKE ne može se primijeniti na grupiranje stupaca kao što je SongTitle. U ovom slučaju dopušteni su samo 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

Kao što je prikazano u prethodnim primjerima, glavna metoda za kreiranje upita u MongoDB-u je db.collection.find(). Ova metoda eksplicitno sadrži naziv kolekcije (music u donjem primjeru), tako da je postavljanje upita za više kolekcija zabranjeno.

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

Čitanje svih redaka tablice

Čitanje svih redaka jednostavno je poseban slučaj obrasca upita koji smo ranije pogledali.

PostgreSQL

SELECT * 
FROM Music;

Cassandra

Slično gornjem primjeru PostgreSQL-a.

MongoDB

db.music.find( {} );

Uređivanje podataka u tablici

PostgreSQL

PostgreSQL daje upute UPDATE za promjenu podataka. Ona nema mogućnosti UPSERT, pa ova izjava neće uspjeti ako red više nije u bazi podataka.

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

Cassandra

Cassandra ima UPDATE sličan PostgreSQL-u. UPDATE ima istu semantiku UPSERT, sličan INSERT.

Slično gornjem primjeru PostgreSQL-a.

MongoDB
Operacija ažuriranje() u MongoDB-u može potpuno ažurirati postojeći dokument ili ažurirati samo određena polja. Prema zadanim postavkama ažurira samo jedan dokument s onemogućenom semantikom UPSERT. Ažuriranje više dokumenata i slično ponašanje UPSERT može se primijeniti postavljanjem dodatnih oznaka za operaciju. Na primjer, u primjeru ispod, žanr određenog izvođača ažurira se na temelju njegove pjesme.

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

Uklanjanje podataka iz tablice

PostgreSQL

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

Cassandra

Slično gornjem primjeru PostgreSQL-a.

MongoDB

MongoDB ima dvije vrste operacija za brisanje dokumenata − deleteOne() /deleteMany() и ukloniti(). Obje vrste brišu dokumente, ali vraćaju različite rezultate.

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

Brisanje tablice

PostgreSQL

DROP TABLE Music;

Cassandra

Slično gornjem primjeru PostgreSQL-a.

MongoDB

db.music.drop();

Zaključak

Rasprava o izboru između SQL-a i NoSQL-a traje već više od 10 godina. Dva su glavna aspekta ove rasprave: arhitektura baze podataka (monolitni, transakcijski SQL u odnosu na distribuirani, netransakcijski NoSQL) i pristup dizajnu baze podataka (modeliranje vaših podataka u SQL-u u odnosu na modeliranje vaših upita u NoSQL-u).

S distribuiranom transakcijskom bazom podataka kao što je YugaByte DB, rasprava o arhitekturi baze podataka može se lako zaustaviti. Kako količine podataka postaju veće od onoga što se može zapisati u jedan čvor, postaje neophodna potpuno distribuirana arhitektura koja podržava skalabilnost linearnog pisanja s automatskim dijeljenjem/rebalansom.

Osim toga, kako je navedeno u jednom od članaka Google Cloud,Transakcijske, jako konzistentne arhitekture sada se više koriste za pružanje bolje agilnosti razvoja nego netransakcijske, ,na kraju konzistentne arhitekture.

Vraćajući se na raspravu o dizajnu baze podataka, pošteno je reći da su oba pristupa dizajnu (SQL i NoSQL) neophodna za svaku složenu aplikaciju u stvarnom svijetu. Pristup SQL "modeliranja podataka" omogućuje programerima da lakše zadovolje promjenjive poslovne zahtjeve, dok pristup NoSQL "modeliranja upita" omogućuje istim programerima da rade na velikim količinama podataka uz nisku latenciju i visoku propusnost. Iz tog razloga YugaByte DB pruža SQL i NoSQL API-je u zajedničkoj jezgri, umjesto da promovira jedan od pristupa. Osim toga, pružajući kompatibilnost s popularnim jezicima baza podataka uključujući PostgreSQL i Cassandra, YugaByte DB osigurava da programeri ne moraju učiti drugi jezik za rad s distribuiranim, visoko konzistentnim motorom baze podataka.

U ovom smo članku pogledali kako se osnove dizajna baze podataka razlikuju između PostgreSQL-a, Cassandre i MongoDB-a. U budućim člancima zaronit ćemo u napredne koncepte dizajna kao što su indeksi, transakcije, JOIN-ovi, TTL direktive i JSON dokumenti.

Želimo vam ugodan ostatak vikenda i pozivamo vas besplatni webinar, koji će se održati 14. svibnja.

Izvor: www.habr.com

Dodajte komentar