TL; DR: JSONB voi yksinkertaistaa tietokantaskeeman kehitystä huomattavasti kyselyn suorituskyvystä tinkimättä.
Esittely
Otetaan klassinen esimerkki relaatiotietokannan (tietokannan) luultavasti yhdestä maailman vanhimmista käyttötapauksista: meillä on entiteetti, ja meidän on tallennettava tämän entiteetin tietyt ominaisuudet (attribuutit). Mutta kaikilla esiintymillä ei välttämättä ole samoja ominaisuuksia, ja uusia ominaisuuksia voidaan lisätä tulevaisuudessa.
Helpoin tapa ratkaista tämä ongelma on luoda tietokantataulukkoon sarake kullekin ominaisuuden arvolle ja yksinkertaisesti täyttää ne, jotka tarvitaan tietylle entiteettiinstanssille. Loistava! Ongelma ratkaistu... kunnes taulukossasi on miljoonia tietueita ja sinun on lisättävä uusi tietue.
Harkitse EAV-kuviota (
En kuitenkaan kirjoittaisi tätä viestiä, ellei EVA-lähestymistavalla olisi joitain huonoja puolia. Joten esimerkiksi yhden tai useamman entiteetin saamiseksi, joilla kullakin on 1 attribuutti, kyselyssä tarvitaan 2 liitosta: ensimmäinen on liitos attribuuttitaulukon kanssa, toinen on liitos arvotaulukon kanssa. Jos entiteetillä on 2 attribuuttia, tarvitaan 4 liittämistä! Lisäksi kaikki attribuutit tallennetaan tyypillisesti merkkijonoina, mikä johtaa sekä tuloksen että WHERE-lauseen tyyppivaltaan. Jos kirjoitat paljon kyselyitä, tämä on melko turhaa resurssien käytön kannalta.
Näistä ilmeisistä puutteista huolimatta EAV:ta on käytetty pitkään tällaisten ongelmien ratkaisemiseen. Nämä olivat väistämättömiä puutteita, eikä parempaa vaihtoehtoa ollut.
Mutta sitten uusi "teknologia" ilmestyi PostgreSQL: hen...
PostgreSQL 9.4:stä alkaen JSONB-tietotyyppi lisättiin JSON-binääritietojen tallentamiseen. Vaikka JSONin tallentaminen tässä muodossa vie tavallisesti hieman enemmän tilaa ja aikaa kuin pelkän tekstin JSON, toimintojen suorittaminen sillä on paljon nopeampaa. JSONB tukee myös indeksointia, mikä tekee kyselyistä entistä nopeampia.
JSONB-tietotyypin avulla voimme korvata hankalan EAV-kuvion lisäämällä vain yhden JSONB-sarakkeen entiteettitaulukkoomme, mikä yksinkertaistaa huomattavasti tietokannan suunnittelua. Mutta monet väittävät, että tähän pitäisi liittyä tuottavuuden lasku... Siksi kirjoitin tämän artikkelin.
Testitietokannan perustaminen
Tätä vertailua varten loin tietokannan PostgreSQL 9.5:n tuoreelle asennukselle 80 dollarin koontiversiolle
CREATE TABLE entity (
id SERIAL PRIMARY KEY,
name TEXT,
description TEXT
);
CREATE TABLE entity_attribute (
id SERIAL PRIMARY KEY,
name TEXT
);
CREATE TABLE entity_attribute_value (
id SERIAL PRIMARY KEY,
entity_id INT REFERENCES entity(id),
entity_attribute_id INT REFERENCES entity_attribute(id),
value TEXT
);
Alla on taulukko, johon samat tiedot tallennetaan, mutta attribuutit JSONB-tyyppisessä sarakkeessa - ominaisuudet.
CREATE TABLE entity_jsonb (
id SERIAL PRIMARY KEY,
name TEXT,
description TEXT,
properties JSONB
);
Näyttää paljon yksinkertaisemmalta, eikö? Sitten se lisättiin entiteettitaulukoihin (kokonaisuus & entity_jsonb) 10 miljoonaa tietuetta, ja vastaavasti taulukko täytettiin samoilla tiedoilla käyttämällä EAV-mallia ja lähestymistapaa JSONB-sarakkeella - entity_jsonb.properties. Näin ollen saimme useita eri tietotyyppejä koko kiinteistöjoukosta. Esimerkkitiedot:
{
id: 1
name: "Entity1"
description: "Test entity no. 1"
properties: {
color: "red"
lenght: 120
width: 3.1882420
hassomething: true
country: "Belgium"
}
}
Joten nyt meillä on samat tiedot molemmista vaihtoehdoista. Aloitetaan toteutusten vertailu työssä!
Yksinkertaista suunnitteluasi
Aiemmin kerrottiin, että tietokannan suunnittelua yksinkertaistettiin huomattavasti: yksi taulukko käyttämällä JSONB-saraketta ominaisuuksille sen sijaan, että olisi käytetty kolme taulukkoa EAV:lle. Mutta miten tämä näkyy pyynnöissä? Yhden kokonaisuuden omaisuuden päivittäminen näyttää tältä:
-- EAV
UPDATE entity_attribute_value
SET value = 'blue'
WHERE entity_attribute_id = 1
AND entity_id = 120;
-- JSONB
UPDATE entity_jsonb
SET properties = jsonb_set(properties, '{"color"}', '"blue"')
WHERE id = 120;
Kuten näette, viimeinen pyyntö ei näytä yksinkertaisemmalta. JSONB-objektin ominaisuuden arvon päivittämiseksi meidän on käytettävä toimintoa
Valitse nyt juuri päivittämämme entiteetti sen uuden värin perusteella:
-- EAV
SELECT e.name
FROM entity e
INNER JOIN entity_attribute_value eav ON e.id = eav.entity_id
INNER JOIN entity_attribute ea ON eav.entity_attribute_id = ea.id
WHERE ea.name = 'color' AND eav.value = 'blue';
-- JSONB
SELECT name
FROM entity_jsonb
WHERE properties ->> 'color' = 'blue';
Uskon, että voimme olla samaa mieltä siitä, että toinen on lyhyempi (ei liittymistä!) ja siksi luettavampi. JSONB voittaa täällä! Käytämme JSON ->> -operaattoria saadaksemme värin tekstiarvona JSONB-objektista. On myös toinen tapa saavuttaa sama tulos JSONB-mallissa käyttämällä @>-operaattoria:
-- JSONB
SELECT name
FROM entity_jsonb
WHERE properties @> '{"color": "blue"}';
Tämä on hieman monimutkaisempi: tarkistamme, sisältääkö ominaisuudet-sarakkeen JSON-objekti objektin, joka on @>-operaattorin oikealla puolella. Vähemmän luettava, tuottavampi (katso alla).
Tehdään JSONB:n käytöstä entistä helpompaa, kun sinun on valittava useita ominaisuuksia kerralla. Tässä JSONB-lähestymistapa todella tulee esiin: valitsemme yksinkertaisesti ominaisuudet lisäsarakkeiksi tulosjoukostamme ilman liitoksia:
-- JSONB
SELECT name
, properties ->> 'color'
, properties ->> 'country'
FROM entity_jsonb
WHERE id = 120;
EAV:n kanssa tarvitset 2 liitosta jokaista kohdetta kohden. Mielestäni yllä olevat kyselyt osoittavat suurta yksinkertaistamista tietokannan suunnittelussa. Katso lisää esimerkkejä JSONB-kyselyjen kirjoittamisesta, myös sisään
Nyt on aika puhua suorituskyvystä.
Suorituskyky
Vertailemaan suorituskykyä käytin
Tietojen päivitys näytti seuraavat tulokset ajassa (ms). Huomaa, että asteikko on logaritminen:
Näemme, että JSONB on paljon (> 50000-x) nopeampi kuin EAV, jos et käytä indeksejä yllä mainitusta syystä. Kun indeksoimme sarakkeita ensisijaisilla avaimilla, ero lähes häviää, mutta JSONB on silti 1,3 kertaa nopeampi kuin EAV. Huomaa, että JSONB-sarakkeen indeksillä ei ole vaikutusta tähän, koska emme käytä ominaisuussaraketta arviointiehdoissa.
Kun valitsemme tiedot kiinteistön arvon perusteella, saamme seuraavat tulokset (normaali mittakaava):
Voit huomata, että JSONB toimii taas nopeammin kuin EAV ilman indeksejä, mutta kun EAV indekseillä, se toimii silti nopeammin kuin JSONB. Mutta sitten huomasin, että JSONB-kyselyiden ajat olivat samat, mikä sai minut toteamaan, että GIN-indeksit eivät toimi. Ilmeisesti kun käytät GIN-indeksiä sarakkeessa, jossa on täytetyt ominaisuudet, se tulee voimaan vain käytettäessä include-operaattoria @>. Käytin tätä uudessa testissä ja sillä oli valtava vaikutus aikaan: vain 0,153 ms! Tämä on 15000 25000 kertaa nopeampi kuin EAV ja XNUMX XNUMX kertaa nopeampi kuin ->> -operaattori.
Mielestäni se oli tarpeeksi nopea!
Tietokantataulukon koko
Verrataan molempien lähestymistapojen taulukkokokoja. Psql:ssä voimme näyttää kaikkien taulukoiden ja indeksien koon komennolla dti+
EAV-lähestymistavassa taulukoiden koot ovat noin 3068 Mt ja indeksit jopa 3427 Mt, yhteensä 6,43 Gt. JSONB-lähestymistapa käyttää 1817 Mt taulukkoon ja 318 Mt indekseihin, mikä on 2,08 Gt. Se osoittautuu 3 kertaa vähemmän! Tämä seikka yllätti minut hieman, koska tallennamme ominaisuuksien nimet jokaiseen JSONB-objektiin.
Mutta silti, luvut puhuvat puolestaan: EAV:ssa tallennamme 2 kokonaislukua vieraa-avainta attribuutin arvoa kohden, jolloin saadaan 8 tavua lisätietoa. Lisäksi EAV tallentaa kaikki ominaisuusarvot tekstinä, kun taas JSONB käyttää numeerisia ja boolean-arvoja sisäisesti mahdollisuuksien mukaan, mikä johtaa pienempään jalanjälkeen.
Tulokset
Kaiken kaikkiaan mielestäni kokonaisuuden ominaisuuksien tallentaminen JSONB-muodossa voi tehdä tietokannan suunnittelusta ja ylläpidosta paljon helpompaa. Jos suoritat paljon kyselyjä, kaiken pitäminen samassa taulukossa entiteetin kanssa toimii itse asiassa tehokkaammin. Ja se, että tämä yksinkertaistaa tietojen välistä vuorovaikutusta, on jo plussaa, mutta tuloksena oleva tietokanta on 3 kertaa pienempi.
Myös suoritettujen testien perusteella voimme päätellä, että suorituskykyhäviöt ovat erittäin merkityksettömiä. Joissakin tapauksissa JSONB on jopa nopeampi kuin EAV, mikä tekee siitä vielä paremman. Tämä vertailuarvo ei tietenkään kata kaikkia näkökohtia (esim. entiteetit, joilla on erittäin suuri määrä ominaisuuksia, olemassa olevan datan ominaisuuksien lukumäärän merkittävä kasvu,...), joten jos sinulla on ehdotuksia niiden parantamiseksi , jätä rohkeasti kommentteihin!
Lähde: will.com