Databas Design Fundamentals - Jämföra PostgreSQL, Cassandra och MongoDB

Hej kompisar. Innan vi åker till den andra delen av majlovet delar vi med oss ​​av materialet som vi översatte i väntan på lanseringen av en ny stream på kursen "Relationell DBMS".

Databas Design Fundamentals - Jämföra PostgreSQL, Cassandra och MongoDB

Applikationsutvecklare lägger ner mycket tid på att jämföra flera operativa databaser för att välja den som bäst passar den avsedda arbetsbelastningen. Behoven kan omfatta förenklad datamodellering, transaktionsgarantier, läs/skrivprestanda, horisontell skalning och feltolerans. Traditionellt börjar valet med databaskategorin, SQL eller NoSQL, eftersom varje kategori presenterar en tydlig uppsättning avvägningar. Hög prestanda i form av låg latens och hög genomströmning ses i allmänhet som ett icke-avvägningskrav och är därför väsentligt för alla exempeldatabas.

Syftet med den här artikeln är att hjälpa applikationsutvecklare att göra rätt val mellan SQL och NoSQL i samband med applikationsdatamodellering. Vi ska titta på en SQL-databas, nämligen PostgreSQL, och två NoSQL-databaser, Cassandra och MongoDB, för att täcka grunderna i databasdesign, som att skapa tabeller, fylla i dem, läsa data från en tabell och ta bort den. I nästa artikel kommer vi att se till att titta på index, transaktioner, JOINs, TTL-direktiv och JSON-baserad databasdesign.

Vad är skillnaden mellan SQL och NoSQL?

SQL-databaser ökar applikationsflexibiliteten genom ACID-transaktionsgarantier, såväl som deras förmåga att söka efter data med JOINs på oväntade sätt ovanpå befintliga normaliserade relationsdatabasmodeller.

Med tanke på deras monolitiska/ennodsarkitektur och användning av en master-slav-replikeringsmodell för redundans, saknar traditionella SQL-databaser två viktiga funktioner - linjär skrivskalbarhet (d.v.s. automatisk partitionering över flera noder) och automatisk/noll dataförlust. Detta innebär att mängden mottagen data inte kan överstiga den maximala skrivgenomströmningen för en enskild nod. Dessutom måste viss tillfällig dataförlust tas med i beräkningen vid feltolerans (i en delad-ingenting-arkitektur). Här måste du komma ihåg att de senaste commits ännu inte har återspeglas i slavkopian. Uppdateringar utan driftstopp är också svåra att uppnå i SQL-databaser.

NoSQL-databaser är vanligtvis distribuerade av naturen, d.v.s. i dem är data uppdelad i sektioner och fördelade över flera noder. De kräver denormalisering. Det betyder att den inmatade informationen också måste kopieras flera gånger för att svara på de specifika förfrågningar du skickar. Det övergripande målet är att uppnå hög prestanda genom att minska antalet tillgängliga skärvor under läsningar. Detta innebär att NoSQL kräver att du modellerar dina frågor, medan SQL kräver att du modellerar dina data.

NoSQL fokuserar på att uppnå hög prestanda i ett distribuerat kluster och detta är den underliggande logiken för många avvägningar för databasdesign som inkluderar ACID-transaktionsförlust, JOINs och konsekventa globala sekundära index.

Det finns ett argument att medan NoSQL-databaser ger linjär skrivskalbarhet och hög feltolerans, gör förlusten av transaktionsgarantier dem olämpliga för verksamhetskritiska data.

Följande tabell visar hur datamodellering i NoSQL skiljer sig från SQL.

Databas Design Fundamentals - Jämföra PostgreSQL, Cassandra och MongoDB

SQL och NoSQL: Varför behövs båda?

Verkliga applikationer med ett stort antal användare, som Amazon.com, Netflix, Uber och Airbnb, har till uppgift att utföra komplexa, mångfacetterade uppgifter. Till exempel behöver en e-handelsapplikation som Amazon.com lagra lättvikts, högkritisk data som användarinformation, produkter, beställningar, fakturor, tillsammans med tung, mindre känslig data som produktrecensioner, supportmeddelanden, användaraktivitet, användarrecensioner och rekommendationer. Naturligtvis förlitar sig dessa applikationer på minst en SQL-databas tillsammans med minst en NoSQL-databas. I tvärregionala och globala system fungerar en NoSQL-databas som en geodistribuerad cache för data lagrad i en betrodd käll-SQL-databas som körs i en viss region.

Hur kombinerar YugaByte DB SQL och NoSQL?

YugaByte DB är byggd på en loggorienterad blandad lagringsmotor, auto-sharding, shard distribuerad konsensusreplikering och ACID-distribuerade transaktioner (inspirerad av Google Spanner), världens första öppen källkodsdatabas som samtidigt är kompatibel med NoSQL (Cassandra & Redis ) och SQL (PostgreSQL). Som visas i tabellen nedan lägger YCQL, YugaByte DB API kompatibel med Cassandra, till koncepten med enkel- och flernyckel ACID-transaktioner och globala sekundära index till NoSQL API, och inleder därigenom eran av transaktionella NoSQL-databaser. YCQL, YugaByte DB API som är kompatibel med PostgreSQL, lägger dessutom till koncepten linjär skrivskalning och automatisk feltolerans till SQL API, vilket ger distribuerade SQL-databaser till världen. Eftersom YugaByte DB är transaktionell till sin natur, kan NoSQL API nu användas i samband med uppdragskritiska data.

Databas Design Fundamentals - Jämföra PostgreSQL, Cassandra och MongoDB

Som tidigare nämnts i artikeln "Vi presenterar YSQL: En PostgreSQL-kompatibel distribuerad SQL API för YugaByte DB", valet mellan SQL eller NoSQL i YugaByte DB beror helt på egenskaperna hos den underliggande arbetsbelastningen:

  • Om din primära arbetsbelastning är JOIN-operationer med flera nyckel, då när du väljer YSQL, förstå att dina nycklar kan vara fördelade över flera noder, vilket resulterar i högre latens och/eller lägre genomströmning än NoSQL.
  • Annars väljer du någon av de två NoSQL API:erna, med tanke på att du kommer att få bättre prestanda som ett resultat av frågor som serveras från en nod i taget. YugaByte DB kan fungera som en enda operativ databas för komplexa applikationer i verkligheten som behöver hantera flera arbetsbelastningar samtidigt.

Datamodelleringslabbet i nästa avsnitt är baserat på PostgreSQL och Cassandra API-kompatibla YugaByte DB-databaser, i motsats till inhemska databaser. Detta tillvägagångssätt betonar hur lätt det är att interagera med två olika API:er (på två olika portar) i samma databaskluster, i motsats till att använda helt oberoende kluster av två olika databaser.
I de följande avsnitten tar vi en titt på datamodelleringslabbet för att illustrera skillnaderna och några av de gemensamma kännetecknen för de täckta databaserna.

Datamodelleringslaboratorium

Databasinstallation

Med tanke på betoningen på design av datamodeller (snarare än komplexa distributionsarkitekturer), kommer vi att installera databaser i Docker-behållare på den lokala maskinen och sedan interagera med dem med hjälp av deras respektive kommandoradsskal.

PostgreSQL & Cassandra-kompatibel YugaByte DB-databas

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

Kommandoradsåtkomst

Låt oss ansluta till databaserna med hjälp av kommandoradsskalet för motsvarande API:er.

PostgreSQL

psql är ett kommandoradsskal för att interagera med PostgreSQL. För enkel användning kommer YugaByte DB med psql direkt i bin-mappen.

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

Cassandra

cqlsh är ett kommandoradsskal för att interagera med Cassandra och dess kompatibla databaser via CQL (Cassandra Query Language). För enkel användning kommer YugaByte DB med cqlsh i katalogen bin.
Observera att CQL inspirerades av SQL och har liknande koncept för tabeller, rader, kolumner och index. Men som ett NoSQL-språk lägger det till en viss uppsättning begränsningar, varav de flesta kommer vi också att täcka i andra artiklar.

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

MongoDB

mongo är ett kommandoradsskal för att interagera med MongoDB. Den finns i bin-katalogen för MongoDB-installationen.

docker exec -it my-mongo bash 
cd bin
mongo

Skapa en tabell

Nu kan vi interagera med databasen för att utföra olika operationer med hjälp av kommandoraden. Låt oss börja med att skapa en tabell som lagrar information om låtar skrivna av olika artister. Dessa låtar kan vara en del av ett album. Även valfria attribut för en låt är releaseår, pris, genre och betyg. Vi måste ta hänsyn till ytterligare attribut som kan behövas i framtiden genom fältet "taggar". Den kan lagra semistrukturerad data i form av nyckel-värdepar.

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

Att skapa en tabell i Cassandra är mycket likt PostgreSQL. En av huvudskillnaderna är avsaknaden av integritetsbegränsningar (t.ex. NOT NULL), men detta är applikationens ansvar, inte NoSQL-databasen. Den primära nyckeln består av en partitionsnyckel (kolumnen Artist i exemplet nedan) och en uppsättning klustringskolumner (kolumnen SongTitle i exemplet nedan). Partitionsnyckeln bestämmer vilken partition/shard raden ska placeras i, och klustringskolumnerna anger hur data ska organiseras inom det aktuella fragmentet.

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 organiserar data i databaser (Databas) (liknande Keyspace i Cassandra), där det finns samlingar (liknar tabeller) som innehåller dokument (liknar rader i en tabell). I MongoDB finns det i princip inget behov av att definiera ett initialt schema. Team "använd databas", som visas nedan, instansierar databasen vid det första anropet och ändrar kontexten för den nyskapade databasen. Även samlingar behöver inte skapas explicit, de skapas automatiskt, helt enkelt när du lägger till det första dokumentet i en ny samling. Observera att MongoDB använder testdatabasen som standard, så alla operationer på samlingsnivå utan att ange en specifik databas körs på den som standard.

use myNewDatabase;

Få information om en tabell
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;

Mata in data i en tabell
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

Övergripande uttryck INSERT i Cassandra ser väldigt lik den i PostgreSQL. Det finns dock en stor skillnad i semantik. I Cassandra INSERT är faktiskt en operation UPSERT, där de sista värdena läggs till raden om raden redan finns.

Datainmatning liknar PostgreSQL INSERT ovan

.

MongoDB

Även om MongoDB är en NoSQL-databas som Cassandra, har dess insättningsoperation ingenting gemensamt med Cassandras semantiska beteende. I MongoDB Föra in() har inga möjligheter UPSERT, vilket gör det likt PostgreSQL. Lägger till standarddata utan _idspecified kommer att göra att ett nytt dokument läggs till i samlingen.

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

Tabellfråga

Den kanske viktigaste skillnaden mellan SQL och NoSQL när det gäller frågekonstruktion är språket som används FROM и WHERE. SQL tillåter efter uttryck FROM välj flera tabeller och uttryck med WHERE kan vara av vilken komplexitet som helst (inklusive operationer JOIN mellan borden). NoSQL tenderar dock att lägga en allvarlig begränsning på FROM, och fungerar bara med en angiven tabell, och i WHERE, måste primärnyckeln alltid anges. Detta knyter an till NoSQL-prestandapushen vi pratade om tidigare. Denna önskan leder till varje möjlig minskning av alla interaktioner mellan tabeller och nyckeln. Det kan introducera en stor fördröjning i kommunikationen mellan noderna när man svarar på en förfrågan och är därför bäst att undvika i allmänhet. Till exempel kräver Cassandra att frågor begränsas till vissa operatörer (endast =, IN, <, >, =>, <=) på partitionsnycklar, förutom när du begär ett sekundärt index (endast = operatorn är tillåten här).

PostgreSQL

Nedan finns tre exempel på frågor som enkelt kan köras av en SQL-databas.

  • Visa alla låtar av en artist;
  • Visa alla låtar av artisten som matchar den första delen av titeln;
  • Visa alla låtar av en artist som har ett visst ord i titeln och har ett pris som är lägre än 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

Av PostgreSQL-frågorna som listas ovan fungerar bara den första oförändrad i Cassandra, eftersom operatören LIKE kan inte tillämpas på klustringskolumner som t.ex SongTitle. I det här fallet är endast operatörer tillåtna = и 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

Som visas i de tidigare exemplen är huvudmetoden för att skapa frågor i MongoDB db.collection.find(). Denna metod innehåller uttryckligen namnet på samlingen (music i exemplet nedan), så det är förbjudet att söka efter flera samlingar.

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

Läser alla rader i en tabell

Att läsa alla rader är helt enkelt ett specialfall av frågemönster som vi tittade på tidigare.

PostgreSQL

SELECT * 
FROM Music;

Cassandra

Liknar PostgreSQL-exemplet ovan.

MongoDB

db.music.find( {} );

Redigera data i en tabell

PostgreSQL

PostgreSQL ger instruktioner UPDATE för att ändra data. Hon har inga möjligheter UPSERT, så denna sats misslyckas om raden inte längre finns i databasen.

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

Cassandra

Cassandra har UPDATE liknande PostgreSQL. UPDATE har samma semantik UPSERT, liknande INSERT.

Liknar PostgreSQL-exemplet ovan.

MongoDB
Operation uppdatering() i MongoDB kan helt uppdatera ett befintligt dokument eller uppdatera endast vissa fält. Som standard uppdaterar den bara ett dokument med semantik inaktiverad UPSERT. Uppdatering av flera dokument och liknande beteende UPSERT kan tillämpas genom att ställa in ytterligare flaggor för operationen. Till exempel, i exemplet nedan uppdateras genren för en specifik artist baserat på hans låt.

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

Ta bort data från en tabell

PostgreSQL

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

Cassandra

Liknar PostgreSQL-exemplet ovan.

MongoDB

MongoDB har två typer av operationer för att radera dokument − deleteOne() /deleteMany() и avlägsna(). Båda typerna tar bort dokument men ger olika resultat.

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

Ta bort en tabell

PostgreSQL

DROP TABLE Music;

Cassandra

Liknar PostgreSQL-exemplet ovan.

MongoDB

db.music.drop();

Slutsats

Debatten om att välja mellan SQL och NoSQL har rasat i mer än 10 år. Det finns två huvudaspekter i denna debatt: databasmotorarkitektur (monolitisk, transaktionsbaserad SQL vs distribuerad, icke-transaktionell NoSQL) och databasdesignmetoden (modellera dina data i SQL vs modellering av dina frågor i NoSQL).

Med en distribuerad transaktionsdatabas som YugaByte DB kan debatten om databasarkitektur lätt läggas ner. När datavolymer blir större än vad som kan skrivas till en enskild nod, blir en fullt distribuerad arkitektur som stöder linjär skrivskalbarhet med automatisk skärning/ombalansering nödvändig.

Dessutom, som det står i en av artiklarna Google Cloud,Transaktionella, starkt konsekventa arkitekturer används nu mer för att ge bättre utvecklingsflexibilitet än icke-transaktionella, så småningom konsekventa arkitekturer.

För att komma tillbaka till diskussionen om databasdesign, är det rimligt att säga att båda designmetoderna (SQL och NoSQL) är nödvändiga för alla komplexa verkliga tillämpningar. SQL-metoden "datamodellering" gör det möjligt för utvecklare att lättare möta förändrade affärskrav, medan NoSQL-metoden "frågemodellering" tillåter samma utvecklare att arbeta på stora datamängder med låg latens och hög genomströmning. Det är av denna anledning som YugaByte DB tillhandahåller SQL- och NoSQL-API:er i en gemensam kärna, snarare än att främja ett av tillvägagångssätten. Dessutom, genom att tillhandahålla kompatibilitet med populära databasspråk, inklusive PostgreSQL och Cassandra, säkerställer YugaByte DB att utvecklare inte behöver lära sig ett annat språk för att arbeta med en distribuerad, mycket konsekvent databasmotor.

I den här artikeln tittade vi på hur grunderna för databasdesign skiljer sig mellan PostgreSQL, Cassandra och MongoDB. I framtida artiklar kommer vi att dyka in i avancerade designkoncept som index, transaktioner, JOINs, TTL-direktiv och JSON-dokument.

Vi önskar dig en trevlig helg och inbjuder dig till gratis webbseminarium, som äger rum den 14 maj.

Källa: will.com

Lägg en kommentar