Hallo vrienden. Voordat we naar het tweede deel van de meivakantie vertrekken, delen we met u het materiaal dat we hebben vertaald in afwachting van de lancering van een nieuwe stream op de cursus
Applicatieontwikkelaars besteden veel tijd aan het vergelijken van meerdere operationele databases om de database te selecteren die het beste past bij de beoogde werklast. Behoeften kunnen bestaan uit vereenvoudigde datamodellering, transactionele garanties, lees-/schrijfprestaties, horizontale schaling en fouttolerantie. Traditioneel begint de keuze met de databasecategorie, SQL of NoSQL, omdat elke categorie een duidelijke reeks afwegingen met zich meebrengt. Hoge prestaties in termen van lage latentie en hoge doorvoer worden over het algemeen gezien als een niet-traditionele vereiste en zijn daarom essentieel voor elke voorbeelddatabase.
Het doel van dit artikel is om applicatieontwikkelaars te helpen de juiste keuze te maken tussen SQL en NoSQL in de context van applicatiedatamodellering. We zullen kijken naar één SQL-database, namelijk PostgreSQL, en twee NoSQL-databases, Cassandra en MongoDB, om de basisprincipes van databaseontwerp te behandelen, zoals het maken van tabellen, het vullen ervan, het lezen van gegevens uit een tabel en het verwijderen ervan. In het volgende artikel zullen we zeker kijken naar indexen, transacties, JOIN's, TTL-richtlijnen en op JSON gebaseerd databaseontwerp.
Wat is het verschil tussen SQL en NoSQL?
SQL-databases vergroten de applicatieflexibiliteit door middel van ACID-transactiegaranties, evenals hun vermogen om gegevens op te vragen met behulp van JOIN's op onverwachte manieren bovenop bestaande genormaliseerde relationele databasemodellen.
Gegeven hun monolithische architectuur met één knooppunt en het gebruik van een master-slave-replicatiemodel voor redundantie, missen traditionele SQL-databases twee belangrijke kenmerken: lineaire schrijfschaalbaarheid (d.w.z. automatische partitie over meerdere knooppunten) en automatisch/geen gegevensverlies. Dit betekent dat de hoeveelheid ontvangen gegevens de maximale schrijfdoorvoer van een enkel knooppunt niet kan overschrijden. Bovendien moet bij de fouttolerantie (in een architectuur waarbij niets wordt gedeeld) rekening worden gehouden met enig tijdelijk gegevensverlies. Hier moet je in gedachten houden dat recente commits nog niet zijn weerspiegeld in de slave-kopie. Ook in SQL-databases zijn niet-downtime-updates moeilijk te realiseren.
NoSQL-databases worden meestal van nature gedistribueerd, d.w.z. daarin worden gegevens verdeeld in secties en verdeeld over verschillende knooppunten. Ze vereisen denormalisatie. Dit betekent dat de ingevoerde gegevens ook meerdere keren moeten worden gekopieerd om te kunnen reageren op de specifieke verzoeken die u verzendt. Het algemene doel is om hoge prestaties te verkrijgen door het aantal shards dat beschikbaar is tijdens het lezen te verminderen. Dit houdt in dat NoSQL vereist dat u uw query's modelleert, terwijl SQL vereist dat u uw gegevens modelleert.
NoSQL richt zich op het bereiken van hoge prestaties in een gedistribueerd cluster en dit is de onderliggende reden voor veel compromissen bij het ontwerpen van databases, waaronder ACID-transactieverlies, JOIN's en consistente wereldwijde secundaire indexen.
Er is een argument dat hoewel NoSQL-databases lineaire schrijfschaalbaarheid en hoge fouttolerantie bieden, het verlies van transactionele garanties ze ongeschikt maakt voor bedrijfskritische gegevens.
De volgende tabel laat zien hoe gegevensmodellering in NoSQL verschilt van SQL.
SQL en NoSQL: waarom zijn beide nodig?
Real-world applicaties met grote aantallen gebruikers, zoals Amazon.com, Netflix, Uber en Airbnb, zijn belast met het uitvoeren van complexe, veelzijdige taken. Een e-commerce-applicatie als Amazon.com moet bijvoorbeeld lichtgewicht, zeer kritische gegevens opslaan, zoals gebruikersinformatie, producten, bestellingen, facturen, samen met zware, minder gevoelige gegevens zoals productrecensies, ondersteuningsberichten, gebruikersactiviteit, gebruikersrecensies en aanbevelingen. Uiteraard zijn deze applicaties afhankelijk van ten minste één SQL-database en ten minste één NoSQL-database. In interregionale en mondiale systemen functioneert een NoSQL-database als een geografisch gedistribueerde cache voor gegevens die zijn opgeslagen in een vertrouwde SQL-brondatabase die in een bepaalde regio wordt uitgevoerd.
Hoe combineert YugaByte DB SQL en NoSQL?
Gebouwd op een log-georiënteerde mixed storage-engine, auto-sharding, sharded gedistribueerde consensusreplicatie en ACID gedistribueerde transacties (geïnspireerd door Google Spanner), is YugaByte DB 's werelds eerste open source database die tegelijkertijd compatibel is met NoSQL (Cassandra & Redis) en SQL (PostgreSQL). Zoals weergegeven in de onderstaande tabel voegt YCQL, de YugaByte DB API die compatibel is met Cassandra, de concepten van ACID-transacties met één en meerdere sleutels en globale secundaire indexen toe aan de NoSQL API, waarmee het tijdperk van transactionele NoSQL-databases wordt ingeluid. Bovendien voegt YCQL, de YugaByte DB API die compatibel is met PostgreSQL, de concepten van lineaire schrijfschaling en automatische fouttolerantie toe aan de SQL API, waardoor gedistribueerde SQL-databases naar de wereld worden gebracht. Omdat YugaByte DB transactioneel van aard is, kan de NoSQL API nu worden gebruikt in de context van bedrijfskritische gegevens.
Zoals eerder in het artikel vermeld
- Als uw primaire werklast bestaat uit JOIN-bewerkingen met meerdere sleutels, moet u er bij het kiezen van YSQL rekening mee houden dat uw sleutels over meerdere knooppunten kunnen worden verdeeld, wat resulteert in een hogere latentie en/of lagere doorvoer dan NoSQL.
- Kies anders een van de twee NoSQL-API's, waarbij u er rekening mee moet houden dat u betere prestaties krijgt als gevolg van zoekopdrachten die vanaf één knooppunt tegelijk worden aangeboden. YugaByte DB kan dienen als een enkele operationele database voor real-world, complexe applicaties die meerdere workloads tegelijkertijd moeten beheren.
Het lab voor gegevensmodellering in de volgende sectie is gebaseerd op PostgreSQL- en Cassandra API-compatibele YugaByte DB-databases, in tegenstelling tot native databases. Deze aanpak benadrukt het gemak van interactie met twee verschillende API's (op twee verschillende poorten) van hetzelfde databasecluster, in tegenstelling tot het gebruik van volledig onafhankelijke clusters van twee verschillende databases.
In de volgende secties bekijken we het datamodelleringslab om de verschillen en enkele overeenkomsten tussen de behandelde databases te illustreren.
Laboratorium voor gegevensmodellering
Database-installatie
Gezien de nadruk op het ontwerp van datamodellen (in plaats van complexe implementatiearchitecturen), zullen we databases in Docker-containers op de lokale machine installeren en er vervolgens mee communiceren met behulp van hun respectievelijke opdrachtregelshells.
PostgreSQL & Cassandra-compatibele 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
Toegang via de opdrachtregel
Laten we verbinding maken met de databases met behulp van de opdrachtregelshell voor de bijbehorende API's.
PostgreSQL
docker exec -it yb-postgres-n1 /home/yugabyte/postgres/bin/psql -p 5433 -U postgres
Cassandra
cqlsh
in de catalogus bin
.
Merk op dat CQL is geïnspireerd door SQL en vergelijkbare concepten heeft van tabellen, rijen, kolommen en indexen. Als NoSQL-taal voegt het echter een aantal beperkingen toe, waarvan we de meeste ook in andere artikelen zullen bespreken.
docker exec -it yb-tserver-n1 /home/yugabyte/bin/cqlsh
MongoDB
docker exec -it my-mongo bash
cd bin
mongo
Een tabel maken
Nu kunnen we communiceren met de database om verschillende bewerkingen uit te voeren via de opdrachtregel. Laten we beginnen met het maken van een tabel waarin informatie wordt opgeslagen over nummers die door verschillende artiesten zijn geschreven. Deze nummers kunnen deel uitmaken van een album. Ook optionele attributen voor een nummer zijn het jaar van uitgave, prijs, genre en beoordeling. We moeten rekening houden met aanvullende attributen die in de toekomst mogelijk nodig zijn via het veld 'tags'. Het kan semi-gestructureerde gegevens opslaan in de vorm van sleutel-waardeparen.
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
Het maken van een tabel in Cassandra lijkt sterk op PostgreSQL. Een van de belangrijkste verschillen is het ontbreken van integriteitsbeperkingen (bijvoorbeeld NOT NULL), maar dit is de verantwoordelijkheid van de applicatie, niet van de NoSQL-database. De primaire sleutel bestaat uit een partitiesleutel (de kolom Artiest in het onderstaande voorbeeld) en een reeks clusterkolommen (de kolom SongTitle in het onderstaande voorbeeld). De partitiesleutel bepaalt in welke partitie/shard de rij moet worden geplaatst, en de clusterkolommen geven aan hoe de gegevens binnen de huidige shard moeten worden georganiseerd.
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 organiseert gegevens in databases (Database) (vergelijkbaar met Keyspace in Cassandra), waar er collecties zijn (vergelijkbaar met tabellen) die documenten bevatten (vergelijkbaar met rijen in een tabel). In MongoDB is het in principe niet nodig om een initieel schema te definiëren. Team "gebruik databank", hieronder weergegeven, instantiëert de database bij de eerste aanroep en wijzigt de context voor de nieuw gemaakte database. Zelfs collecties hoeven niet expliciet te worden aangemaakt; ze worden automatisch aangemaakt, simpelweg wanneer u het eerste document aan een nieuwe collectie toevoegt. Houd er rekening mee dat MongoDB standaard de testdatabase gebruikt, dus elke bewerking op verzamelingsniveau zonder een specifieke database op te geven, wordt er standaard op uitgevoerd.
use myNewDatabase;
Informatie over een tafel opvragen
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;
Gegevens in een tabel invoeren
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
Algemene expressie INSERT
in Cassandra lijkt erg op die in PostgreSQL. Er is echter één groot verschil in semantiek. In Cassandra INSERT
is eigenlijk een operatie UPSERT
, waarbij de laatste waarden aan de rij worden toegevoegd als de rij al bestaat.
Gegevensinvoer is vergelijkbaar met PostgreSQL
INSERT
boven
.
MongoDB
Ook al is MongoDB een NoSQL-database zoals Cassandra, de invoegbewerking heeft niets gemeen met het semantische gedrag van Cassandra. In MongoDB UPSERT
, waardoor het vergelijkbaar is met PostgreSQL. Standaardgegevens toevoegen zonder _idspecified
zorgt ervoor dat er een nieuw document aan de collectie wordt toegevoegd.
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"
}
}
);
Tabelquery
Misschien wel het belangrijkste verschil tussen SQL en NoSQL in termen van queryconstructie is de gebruikte taal FROM
и WHERE
. SQL maakt na-expressie mogelijk FROM
selecteer meerdere tabellen en expressie met WHERE
kan van elke complexiteit zijn (inclusief bewerkingen). JOIN
tussen tafels). NoSQL heeft echter de neiging ernstige beperkingen op te leggen FROM
, en werk alleen met één opgegeven tabel, en in WHERE
, moet de primaire sleutel altijd worden opgegeven. Dit sluit aan bij de prestatieverbetering van NoSQL waar we het eerder over hadden. Deze wens leidt tot elke mogelijke vermindering van elke kruistabel- en kruissleutelinteractie. Het kan een grote vertraging veroorzaken in de communicatie tussen knooppunten bij het reageren op een verzoek en kan daarom in het algemeen het beste worden vermeden. Cassandra vereist bijvoorbeeld dat zoekopdrachten beperkt blijven tot bepaalde operators (alleen =, IN, <, >, =>, <=
) op partitiesleutels, behalve bij het aanvragen van een secundaire index (hier is alleen de operator = toegestaan).
PostgreSQL
Hieronder staan drie voorbeelden van queries die eenvoudig door een SQL-database kunnen worden uitgevoerd.
- Toon alle nummers van een artiest;
- Toon alle nummers van de artiest die overeenkomen met het eerste deel van de titel;
- Toon alle nummers van een artiest met een bepaald woord in de titel en een prijs lager dan 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
Van de hierboven genoemde PostgreSQL-query's zal alleen de eerste onveranderd werken in Cassandra, aangezien de operator LIKE
kan niet worden toegepast op clusterkolommen zoals SongTitle
. In dit geval zijn alleen operators toegestaan =
и 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
Zoals u in de vorige voorbeelden kunt zien, is de belangrijkste methode voor het maken van query's in MongoDB music
in het onderstaande voorbeeld), dus het bevragen van meerdere collecties is niet toegestaan.
db.music.find( {
artist: "No One You Know"
}
);
db.music.find( {
artist: "No One You Know",
songTitle: /Call/
}
);
Alle rijen van een tabel lezen
Het lezen van alle rijen is eenvoudigweg een speciaal geval van het zoekpatroon waar we eerder naar keken.
PostgreSQL
SELECT *
FROM Music;
Cassandra
Vergelijkbaar met het PostgreSQL-voorbeeld hierboven.
MongoDB
db.music.find( {} );
Gegevens in een tabel bewerken
PostgreSQL
PostgreSQL biedt instructies UPDATE
gegevens wijzigen. Ze heeft geen kansen UPSERT
, dus deze instructie mislukt als de rij niet langer in de database staat.
UPDATE Music
SET Genre = 'Disco'
WHERE Artist = 'The Acme Band' AND SongTitle = 'Still In Love';
Cassandra
Cassandra heeft UPDATE
gelijk aan PostgreSQL UPDATE
heeft dezelfde semantiek UPSERT
, leuk vinden INSERT
.
Vergelijkbaar met het PostgreSQL-voorbeeld hierboven.
MongoDB
Operatie UPSERT
. Meerdere documenten bijwerken en soortgelijk gedrag UPSERT
kan worden toegepast door extra vlaggen voor de bewerking in te stellen. In het onderstaande voorbeeld wordt bijvoorbeeld het genre van een specifieke artiest bijgewerkt op basis van zijn nummer.
db.music.update(
{"artist": "The Acme Band"},
{
$set: {
"genre": "Disco"
}
},
{"multi": true, "upsert": true}
);
Gegevens uit een tabel verwijderen
PostgreSQL
DELETE FROM Music
WHERE Artist = 'The Acme Band' AND SongTitle = 'Look Out, World';
Cassandra
Vergelijkbaar met het PostgreSQL-voorbeeld hierboven.
MongoDB
MongoDB heeft twee soorten bewerkingen om documenten te verwijderen −
db.music.deleteMany( {
artist: "The Acme Band"
}
);
Een tabel verwijderen
PostgreSQL
DROP TABLE Music;
Cassandra
Vergelijkbaar met het PostgreSQL-voorbeeld hierboven.
MongoDB
db.music.drop();
Conclusie
Het debat over de keuze tussen SQL en NoSQL woedt al meer dan 10 jaar. Er zijn twee belangrijke aspecten aan dit debat: de architectuur van de database-engine (monolithische, transactionele SQL versus gedistribueerde, niet-transactionele NoSQL) en de databaseontwerpbenadering (het modelleren van uw gegevens in SQL versus het modelleren van uw zoekopdrachten in NoSQL).
Met een gedistribueerde transactionele database zoals YugaByte DB kan het debat over database-architectuur gemakkelijk worden beëindigd. Naarmate de datavolumes groter worden dan wat er naar een enkel knooppunt kan worden geschreven, wordt een volledig gedistribueerde architectuur die lineaire schrijfschaalbaarheid ondersteunt met automatische sharding/herbalancering noodzakelijk.
Trouwens, zoals vermeld in een van de artikelen
Terugkomend op de discussie over databaseontwerp kunnen we eerlijk zeggen dat beide ontwerpbenaderingen (SQL en NoSQL) noodzakelijk zijn voor elke complexe toepassing in de echte wereld. Met de SQL-aanpak voor 'datamodellering' kunnen ontwikkelaars gemakkelijker aan veranderende bedrijfsvereisten voldoen, terwijl de 'querymodellering'-benadering van NoSQL dezelfde ontwikkelaars in staat stelt om met grote hoeveelheden gegevens te werken met een lage latentie en een hoge doorvoer. Het is om deze reden dat YugaByte DB SQL- en NoSQL-API's in een gemeenschappelijke kern aanbiedt, in plaats van een van de benaderingen te promoten. Door compatibiliteit te bieden met populaire databasetalen, waaronder PostgreSQL en Cassandra, zorgt YugaByte DB er bovendien voor dat ontwikkelaars geen andere taal hoeven te leren om met een gedistribueerde, zeer consistente database-engine te werken.
In dit artikel hebben we gekeken naar hoe de basisprincipes van databaseontwerp verschillen tussen PostgreSQL, Cassandra en MongoDB. In toekomstige artikelen zullen we dieper ingaan op geavanceerde ontwerpconcepten zoals indexen, transacties, JOIN's, TTL-richtlijnen en JSON-documenten.
Wij wensen u een fijne rest van het weekend en nodigen u graag uit
Bron: www.habr.com