Database Design Fundamentals - Sammenligning af PostgreSQL, Cassandra og MongoDB

Hej venner. Inden vi tager afsted til anden del af majferien, deler vi det materiale med dig, som vi har oversat i forventning om lanceringen af ​​en ny stream til den hastighed "Relationel DBMS".

Database Design Fundamentals - Sammenligning af PostgreSQL, Cassandra og MongoDB

Applikationsudviklere bruger meget tid på at sammenligne flere operationelle databaser for at vælge den, der fungerer bedst til deres tilsigtede arbejdsbyrde. Behovene kan omfatte forenklet datamodellering, transaktionsgarantier, læse-/skriveydelse, horisontal skalering og fejltolerance. Traditionelt begynder valget med kategorien database, SQL eller NoSQL, da hver kategori giver et klart sæt af afvejninger. Høj ydeevne i form af lav latens og høj gennemløb ses generelt som et krav, der ikke kan kompromitteres og er derfor afgørende for enhver database i prøven.

Formålet med denne artikel er at hjælpe applikationsudviklere med at træffe det rigtige valg mellem SQL og NoSQL i forbindelse med applikationsdatamodellering. Vi vil se på én SQL-database, nemlig PostgreSQL, og to NoSQL-databaser, Cassandra og MongoDB, for at dække det grundlæggende i databasedesign, såsom at oprette tabeller, udfylde dem, læse data fra en tabel og slette dem. I den næste artikel vil vi helt sikkert se på indekser, transaktioner, JOINs, TTL-direktiver og databasedesign baseret på JSON.

Hvad er forskellen mellem SQL og NoSQL?

SQL-databaser øger applikationsfleksibiliteten gennem ACID-transaktionsgarantier, såvel som deres evne til at forespørge data ved hjælp af JOINs på uventede måder oven på eksisterende normaliserede relationsdatabasemodeller.

På grund af deres monolitiske/single node-arkitektur og brug af en master-slave-replikeringsmodel til redundans, mangler traditionelle SQL-databaser to vigtige funktioner - lineær skriveskalerbarhed (dvs. automatisk opdeling på tværs af flere noder) og automatisk/nul datatab. Dette betyder, at mængden af ​​modtaget data ikke kan overstige den maksimale skrivegennemstrømning for en enkelt node. Derudover skal der tages højde for et vist midlertidigt tab af data for fejltolerance (i en ikke-delt arkitektur). Her skal du huske på, at de seneste commits endnu ikke er afspejlet i slavekopien. Ingen nedetidsopdateringer er også svære at opnå i SQL-databaser.

NoSQL-databaser er typisk distribueret i naturen, dvs. i dem er dataene opdelt i sektioner og fordelt over flere noder. De kræver denormalisering. Det betyder, at de indtastede data også skal kopieres flere gange for at kunne besvare de specifikke forespørgsler, du sender. Det overordnede mål er at få høj ydeevne ved at reducere antallet af tilgængelige shards på læsetidspunktet. Dette indebærer, at NoSQL kræver, at du modellerer dine forespørgsler, mens SQL kræver, at du modellerer dine data.

NoSQL lægger vægt på at opnå høj ydeevne i en distribueret klynge, og dette er hovedrationalet for mange afvejninger i databasedesign, som inkluderer tab af ACID-transaktioner, JOINs og konsistente globale sekundære indekser.

Der er en opfattelse af, at selvom NoSQL-databaser giver lineær skriveskalerbarhed og høj fejltolerance, gør tabet af transaktionsgarantier dem uegnede til kritiske data.

Følgende tabel viser, hvordan datamodellering i NoSQL adskiller sig fra SQL.

Database Design Fundamentals - Sammenligning af PostgreSQL, Cassandra og MongoDB

SQL og NoSQL: Hvorfor er begge nødvendige?

Virkelige applikationer med et stort antal brugere, såsom Amazon.com, Netflix, Uber og Airbnb, er ansvarlige for at udføre komplekse opgaver af forskellig art. For eksempel skal en e-handelsapplikation som Amazon.com gemme letvægts, meget følsomme data såsom oplysninger om brugere, produkter, ordrer, fakturaer sammen med tunge, men mindre følsomme data såsom produktanmeldelser, supportmeddelelser. , brugeraktivitet , brugeranmeldelser og anbefalinger. Disse applikationer er naturligvis afhængige af mindst én SQL-database sammen med mindst én NoSQL-database. I interregionale og globale systemer fungerer NoSQL-databasen som en geo-distribueret cache for data, der er gemt i en pålidelig kilde, SQL-database, der opererer i en hvilken som helst region.

Hvordan kombinerer YugaByte DB SQL og NoSQL?

YugaByte DB er bygget på en log-orienteret mixed storage-motor, auto-sharding, sharded distribueret konsensusreplikering og ACID-distribuerede transaktioner (inspireret af Google Spanner) og er verdens første open source-database, der samtidigt er NoSQL (Cassandra & Redis) kompatibel. ) og SQL (PostgreSQL). Som vist i nedenstående tabel tilføjer YCQL, en YugaByte DB API, der er kompatibel med Cassandra, koncepterne med enkelt- og multi-nøgle ACID-transaktioner og globale sekundære indekser til NoSQL API, og indvarsler dermed æraen med transaktionelle NoSQL-databaser. YCQL, en YugaByte DB API, der er kompatibel med PostgreSQL, tilføjer derudover koncepterne lineær skriveskalering og automatisk failover til SQL API, hvilket bringer distribuerede SQL-databaser til verden. Da YugaByte DB-databasen i sagens natur er transaktionsbetonet, kan NoSQL API nu bruges i forbindelse med kritiske data.

Database Design Fundamentals - Sammenligning af PostgreSQL, Cassandra og MongoDB

Som tidligere nævnt i artiklen "Introduktion af YSQL: En PostgreSQL-kompatibel distribueret SQL API til YugaByte DB", valget mellem SQL eller NoSQL i YugaByte DB afhænger helt af egenskaberne ved den underliggende arbejdsbyrde:

  • Hvis din primære arbejdsbyrde er JOIN-operationer med flere nøgler, skal du, når du vælger YSQL, være opmærksom på, at dine nøgler kan være spredt over flere noder, hvilket resulterer i højere latenstid og/eller lavere gennemløb end NoSQL.
  • Ellers skal du vælge en af ​​de to NoSQL API'er, idet du husker på, at du vil få bedre ydeevne som et resultat af forespørgsler, der serveres fra én node ad gangen. YugaByte DB kan fungere som en enkelt operationel database til virkelig komplekse applikationer, der skal håndtere flere arbejdsbelastninger på samme tid.

Datamodelleringslaboratoriet i næste afsnit er baseret på PostgreSQL- og Cassandra-kompatible YugaByte DB-database-API'er i modsætning til de originale databaser. Denne tilgang understreger letheden ved at interagere med to forskellige API'er (på to forskellige porte) i den samme databaseklynge, i modsætning til at bruge fuldstændig uafhængige klynger af to forskellige databaser.
I de følgende afsnit tager vi et kig på Data Modeling Lab for at illustrere forskellen og nogle af de fælles træk ved de pågældende databaser.

Data Modeling Lab

Installation af databaser

I betragtning af fokus på datamodeldesign (i stedet for komplekse implementeringsarkitekturer), vil vi installere databaserne i Docker-containere på den lokale maskine og derefter interagere med dem ved hjælp af deres respektive kommandolinjeskaller.

PostgreSQL & Cassandra-kompatibel, YugaByte DB-database

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

Kommandolinjeadgang

Lad os oprette forbindelse til databaserne ved hjælp af kommandolinjeskallen for de respektive API'er.

PostgreSQL

psql er en kommandolinjeskal til interaktion med PostgreSQL. For at lette brugen kommer YugaByte DB med psql lige i bin-mappen.

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

Cassandra

sqlsh er en kommandolinjeskal til at interagere med Cassandra og dens kompatible databaser via CQL (Cassandra Query Language). For at lette brugen medfølger YugaByte DB cqlsh i kataloget bin.
Bemærk, at CQL var inspireret af SQL og har lignende koncepter for tabeller, rækker, kolonner og indekser. Men som et NoSQL-sprog tilføjer det et bestemt sæt begrænsninger, hvoraf de fleste også vil dække i andre artikler.

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

MongoDB

mongo er en kommandolinjeskal til interaktion med MongoDB. Den kan findes i bin-mappen i MongoDB-installationen.

docker exec -it my-mongo bash 
cd bin
mongo

Lav en tabel

Nu kan vi interagere med databasen for at udføre forskellige operationer ved hjælp af kommandolinjen. Lad os starte med at lave en tabel, der gemmer oplysninger om sange skrevet af forskellige kunstnere. Disse sange kan være en del af et album. Også valgfrie egenskaber for sangen er udgivelsesår, pris, genre og rating. Vi er nødt til at tage højde for yderligere attributter, der kan være nødvendige i fremtiden gennem feltet "tags". Det kan gemme semi-strukturerede data som nøgleværdi-par.

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

Oprettelse af en tabel i Cassandra ligner meget PostgreSQL. En af de vigtigste forskelle er fraværet af integritetsbegrænsninger (som NOT NULL), men dette er applikationens ansvar, ikke NoSQL-databasen.. Den primære nøgle består af en partitionsnøgle (Kunstner-kolonnen i eksemplet nedenfor) og et sæt klyngekolonner (SongTitle-kolonnen i eksemplet nedenfor). Partitionsnøglen bestemmer, hvilken partition/shard rækken skal placeres i, og klyngekolonnerne angiver, hvordan dataene skal organiseres i det aktuelle shard.

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 organiserer data i databaser (Database) (svarende til Keyspace i Cassandra), hvor der er samlinger (Samlinger) (svarende til tabeller), der indeholder dokumenter (Dokumenter) (svarende til rækker i en tabel). I MongoDB kræves der i princippet ingen indledende skemadefinition. Hold "brug database", vist nedenfor, instansierer databasen ved det første opkald og ændrer konteksten for den nyoprettede database. Selv samlinger behøver ikke at blive oprettet eksplicit, de oprettes automatisk, lige når det første dokument føjes til en ny samling. Bemærk, at MongoDB bruger en testdatabase som standard, så enhver operation på opsamlingsniveau uden at angive en specifik database vil blive udført i den som standard.

use myNewDatabase;

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

Indtastning af data i en 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

Generelt udtrykket INSERT i Cassandra ligner meget den i PostgreSQL. Der er dog én stor forskel i semantikken. I Cassandra INSERT er faktisk en operation UPSERT, hvor de seneste værdier tilføjes til strengen, hvis strengen allerede eksisterer.

Dataindtastning ligner PostgreSQL INSERT ovenfor

.

MongoDB

Selvom MongoDB er en NoSQL-database som Cassandra, har dens dataindtastningsoperation intet at gøre med Cassandras semantiske adfærd. I MongoDB indsæt () har ingen mulighed UPSERT, hvilket gør det ligner PostgreSQL. Tilføjelse af standarddata uden _idspecified vil resultere i, at et nyt dokument tilføjes til 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"
}
}
);

Tabelforespørgsel

Den måske vigtigste forskel mellem SQL og NoSQL med hensyn til forespørgsel er brugen af FROM и WHERE. SQL tillader efter udtryk FROM vælg flere tabeller, og et udtryk med WHERE kan være af enhver kompleksitet (inklusive operationer JOIN mellem borde). NoSQL har dog en tendens til at sætte en hård grænse for FROM, og arbejde med kun én specificeret tabel, og i WHERE, skal den primære nøgle altid angives. Dette skyldes ønsket om at forbedre ydeevnen af ​​NoSQL, som vi talte om tidligere. Dette ønske fører til enhver mulig reduktion af enhver krydsfane- og krydsnøgleinteraktion. Det kan introducere en stor forsinkelse i kommunikationen mellem knudepunkter, når man svarer på en anmodning, og undgås derfor i princippet bedst. For eksempel kræver Cassandra, at anmodninger er begrænset til visse operatører (kun tilladt =, IN, <, >, =>, <=) på partitionsnøgler, undtagen ved forespørgsel efter et sekundært indeks (kun = operatoren er tilladt her).

PostgreSQL

Følgende er tre eksempler på forespørgsler, der nemt kan udføres af en SQL-database.

  • Vis alle kunstnerens sange;
  • Vis alle sange af kunstneren, der matcher den første del af titlen;
  • Vis alle sange af kunstneren, der har et bestemt ord i titlen og har en pris på under 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

Af de ovenfor anførte PostgreSQL-forespørgsler vil kun den første fungere uændret i Cassandra, fordi sætningen LIKE kan ikke anvendes på klyngekolonner som f.eks SongTitle. I dette tilfælde er kun operatører tilladt = и 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 vist i de foregående eksempler er hovedmetoden til at oprette forespørgsler i MongoDB db.collection.find(). Denne metode indeholder eksplicit navnet på samlingen (music i eksemplet nedenfor), så det er ikke tilladt at forespørge på flere samlinger.

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

Læsning af alle rækker i en tabel

At læse alle rækker er blot et specialtilfælde af det forespørgselsmønster, vi diskuterede tidligere.

PostgreSQL

SELECT * 
FROM Music;

Cassandra

Svarende til PostgreSQL-eksemplet ovenfor.

MongoDB

db.music.find( {} );

Redigering af data i en tabel

PostgreSQL

PostgreSQL giver en erklæring UPDATE at ændre data. Hun har ingen mulighed UPSERT, så denne sætning vil mislykkes, hvis rækken ikke længere er i databasen.

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

Cassandra

Cassandra har UPDATE ligner PostgreSQL. UPDATE har samme semantik UPSERT, synes godt om INSERT.

Svarende til PostgreSQL-eksemplet ovenfor.

MongoDB
Operation opdater () i MongoDB kan den fuldstændig opdatere et eksisterende dokument eller kun opdatere visse felter. Som standard opdaterer den kun ét dokument med semantik deaktiveret UPSERT. Opdater flere dokumenter og lignende adfærd UPSERT kan anvendes ved at indstille yderligere flag for operationen. Som for eksempel i eksemplet nedenfor, opdateres en bestemt kunstners genre af hans sang.

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

Fjernelse af data fra en tabel

PostgreSQL

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

Cassandra

Svarende til PostgreSQL-eksemplet ovenfor.

MongoDB

MongoDB har to typer operationer til sletning af dokumenter − deleteOne() /deleteMany() и fjerne(). Begge typer sletter dokumenter, men returnerer forskellige resultater.

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

Sletning af en tabel

PostgreSQL

DROP TABLE Music;

Cassandra

Svarende til PostgreSQL-eksemplet ovenfor.

MongoDB

db.music.drop();

Konklusion

Debatten om valget mellem SQL og NoSQL har raset i over 10 år. Der er to hovedaspekter i denne debat: databasemotorens arkitektur (monolitisk, transaktionsbaseret SQL vs. distribueret, ikke-transaktionel NoSQL) og tilgangen til databasedesign (datamodellering i SQL vs. modellering af dine forespørgsler i NoSQL).

Med en distribueret transaktionsdatabase som YugaByte DB kan debatten om databasearkitektur let fordrives. Efterhånden som datamængderne bliver større end hvad der kan skrives til en enkelt node, bliver det nødvendigt med en fuldt distribueret arkitektur, der understøtter lineær skriveskalerbarhed med automatisk sharding/rebalancering.

Ud over hvad der blev sagt i en af ​​artiklerne Google CloudTransaktionelle, stærkt konsistente arkitekturer er nu mere udbredt for at give bedre udviklingsfleksibilitet end ikke-transaktionelle, i sidste ende konsistente arkitekturer.

For at vende tilbage til diskussionen om databasedesign, er det rimeligt at sige, at begge designtilgange (SQL og NoSQL) er nødvendige for enhver kompleks applikation i den virkelige verden. SQLs "datamodellering"-tilgang giver udviklere mulighed for lettere at imødekomme skiftende forretningskrav, mens NoSQL's "forespørgselsmodellering"-tilgang tillader de samme udviklere at håndtere store mængder data med lav latenstid og høj gennemstrømning. Det er af denne grund, at YugaByte DB leverer SQL og NoSQL API'er i en fælles kerne og ikke går ind for nogen af ​​tilgangene. Ved at give kompatibilitet med populære databasesprog, herunder PostgreSQL og Cassandra, sikrer YugaByte DB desuden, at udviklere ikke behøver at lære et andet sprog for at arbejde med en distribueret, stærkt konsistent databasemotor.

I denne artikel så vi på, hvordan databasedesign fundamentals adskiller sig mellem PostgreSQL, Cassandra og MongoDB. I de følgende artikler vil vi dykke ned i avancerede designkoncepter såsom indekser, transaktioner, JOINs, TTL-direktiver og JSON-dokumenter.

Vi ønsker dig en god weekend og inviterer dig til gratis webinarsom finder sted den 14. maj.

Kilde: www.habr.com

Tilføj en kommentar