TL; DR: JSONB-k datu-basearen eskemaren garapena asko erraztu dezake kontsultaren errendimendua uko egin gabe.
Sarrera
Eman dezagun seguruenik datu-base erlazional baten (datu-basearen) munduko erabilera kasu zaharrenetako baten adibide klasiko bat: entitate bat dugu, eta entitate horren zenbait propietate (atributu) gorde behar ditugu. Baina baliteke instantzia guztiek ez edukitzea propietate multzo bera, eta baliteke propietate gehiago gehitzea etorkizunean.
Arazo hau konpontzeko modurik errazena datu-base-taulan zutabe bat sortzea da jabetza-balio bakoitzerako, eta besterik gabe, entitate-instantzia zehatz baterako behar direnak betetzea. Bikaina! Arazoa konpondu da... zure taulak milioika erregistro dituen arte eta erregistro berri bat gehitu behar duzun arte.
Demagun EAV eredua (
Hala ere, ez nuke mezu hau idatziko EVAren planteamenduaren alde txarrak egongo ez balira. Beraz, adibidez, bakoitzak atributu 1 duten entitate bat edo gehiago lortzeko, 2 elkartze behar dira kontsultan: lehenengoa atributu-taularekin bateratze bat da, bigarrena balio-taularekin bateratze bat da. Entitate batek 2 atributu baditu, 4 elkartze behar dira! Gainera, atributu guztiak kate gisa gordetzen dira normalean, eta horren ondorioz, emaitza eta WHERE klausula motak igortzen dira. Kontsulta asko idazten badituzu, hori nahiko alferrikakoa da baliabideen erabilerari dagokionez.
Gabezia nabari horiek gorabehera, EAV aspaldidanik erabiltzen da arazo mota hauek konpontzeko. Hauek ezinbesteko gabeziak ziren, eta ez zegoen alternatiba hoberik.
Baina gero "teknologia" berri bat agertu zen PostgreSQL-en...
PostgreSQL 9.4-tik hasita, JSONB datu-mota gehitu zen JSON datu bitarrak gordetzeko. JSON formatu honetan gordetzeak normalean testu arrunteko JSON baino espazio eta denbora pixka bat gehiago hartzen badu ere, eragiketak egitea askoz azkarragoa da. JSONB-k indexatzea ere onartzen du, eta horrek are azkarrago egiten ditu kontsultak.
JSONB datu-motak EAV eredu astuna ordezkatzeko aukera ematen digu JSONB zutabe bakarra gehituz gure entitateen taulan, datu-basearen diseinua asko erraztuz. Baina askoren ustez, horrek produktibitatearen beherakada izan beharko luke... Horregatik idatzi dut artikulu hau.
Proba datu-base bat konfiguratzea
Konparazio honetarako, PostgreSQL 9.5-en instalazio berri batean sortu nuen datu-basea 80 $ eraikitzean.
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
);
Jarraian datu berdinak gordeko diren taula bat dago, baina JSONB motako zutabe batean atributuak dituena - propietate.
CREATE TABLE entity_jsonb (
id SERIAL PRIMARY KEY,
name TEXT,
description TEXT,
properties JSONB
);
Askoz sinpleagoa dirudi, ezta? Ondoren, entitateen tauletan gehitu zen (Erakunde & entity_jsonb) 10 milioi erregistro, eta horren arabera, taula datu berdinekin bete zen EAV eredua eta JSONB zutabe batekin hurbilketa erabiliz - entity_jsonb.properties. Horrela, hainbat datu mota jaso ditugu propietate multzo osoaren artean. Datu laginak:
{
id: 1
name: "Entity1"
description: "Test entity no. 1"
properties: {
color: "red"
lenght: 120
width: 3.1882420
hassomething: true
country: "Belgium"
}
}
Beraz, orain datu berdinak ditugu bi aukeretarako. Has gaitezen inplementazioak konparatzen lanean!
Sinplifikatu zure diseinua
Aurretik esan zen datu-basearen diseinua oso sinplifikatu zela: taula bat, propietateetarako JSONB zutabea erabiliz, EAVrako hiru taula erabili beharrean. Baina nola islatzen da hori eskaeretan? Entitate baten propietatea eguneratzeak honelako itxura du:
-- 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;
Ikus dezakezunez, azken eskaerak ez dirudi sinpleagoa. JSONB objektu bateko propietate baten balioa eguneratzeko funtzioa erabili behar dugu
Orain hauta dezagun eguneratu berri dugun entitatea bere kolore berriaren arabera:
-- 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';
Uste dut ados gaitezkeela bigarrena laburragoa dela (jotzerik ez!), eta, beraz, irakurgarriagoa dela. JSONB-k irabazten du hemen! JSON ->> eragilea erabiltzen dugu kolorea JSONB objektuaren testu-balio gisa lortzeko. JSONB ereduan emaitza bera lortzeko bigarren modu bat ere badago @> eragilea erabiliz:
-- JSONB
SELECT name
FROM entity_jsonb
WHERE properties @> '{"color": "blue"}';
Hau apur bat konplikatuagoa da: bere propietateen zutabean JSON objektuak @> operadorearen eskuinean dagoen objekturen bat duen egiaztatzen dugu. Gutxiago irakurgarria, produktiboagoa (ikus behean).
Egin dezagun JSONB erabiltzea are errazagoa den hainbat propietate aldi berean hautatu behar dituzunean. Hona hemen JSONB ikuspegia benetan sartzen da: propietateak zutabe gehigarri gisa hautatzen ditugu gure emaitza multzoan batu beharrik gabe:
-- JSONB
SELECT name
, properties ->> 'color'
, properties ->> 'country'
FROM entity_jsonb
WHERE id = 120;
EAV-rekin 2 batu beharko dituzu kontsultatu nahi duzun jabetza bakoitzeko. Nire ustez, goiko kontsultek sinplifikazio handia erakusten dute datu baseen diseinuan. Ikusi JSONB kontsultak idazteko adibide gehiago hemen ere
Orain errendimenduaz hitz egiteko garaia da.
produktibitatea
Erabili nuen errendimendua alderatzeko
Datuen eguneraketak denborari dagokionez ondorengo emaitzak erakutsi ditu (ms-tan). Kontuan izan eskala logaritmikoa dela:
Ikusten dugu JSONB EAV baino askoz (> 50000-x) azkarragoa dela indizeak erabiltzen ez badituzu, goian adierazitako arrazoiagatik. Lehen gakoekin zutabeak indexatzen ditugunean, aldea ia desagertzen da, baina JSONB EAV baino 1,3 aldiz azkarragoa da oraindik. Kontuan izan JSONB zutabeko indizeak ez duela eraginik hemen, ebaluazio-irizpideetan propietate-zutabea erabiltzen ez dugulako.
Jabetza-balioan oinarritutako datuak hautatzeko, emaitza hauek lortzen ditugu (eskala normala):
Konturatuko zara berriro JSONB-k EAV baino azkarrago funtzionatzen duela indizerik gabe, baina EAV indizeekin denean, oraindik ere JSONB baino azkarrago funtzionatzen du. Baina gero ikusi nuen JSONB kontsulten denborak berdinak zirela, horrek bultzatu ninduen GIN indizeek ez dutela funtzionatzen. Antza denez, betetako propietateak dituen zutabe batean GIN indizea erabiltzen duzunean, @> include operadorea erabiltzen denean bakarrik hartzen du eragina. Hau proba berri batean erabili nuen eta denboran eragin handia izan zuen: 0,153 ms bakarrik! Hau EAV baino 15000 aldiz azkarragoa da eta ->> operadorea baino 25000 aldiz azkarragoa.
Nahikoa azkarra izan zela uste dut!
Datu-basearen taularen tamaina
Konpara ditzagun bi ikuspegietarako taularen tamainak. psql-en taula eta indize guztien tamaina erakutsi dezakegu komandoa erabiliz dti+
EAV ikuspegirako, taularen tamainak 3068 MB ingurukoak dira eta 3427 MB arteko indizeak 6,43 GB guztira. JSONB ikuspegiak 1817 MB erabiltzen ditu taularako eta 318 MB indizeetarako, hau da, 2,08 GB. 3 aldiz gutxiago ateratzen da! Gertaera honek apur bat harritu nau JSONB objektu guztietan jabetza-izenak gordetzen ditugulako.
Baina, hala ere, zenbakiek beren kabuz hitz egiten dute: EAVn 2 osoko atzerriko gako gordetzen ditugu atributu-balio bakoitzeko, eta ondorioz 8 byte datu gehigarri sortzen dira. Gainera, EAV-k propietate-balio guztiak testu gisa gordetzen ditu, eta JSONB-k, berriz, zenbakizko eta boolear balioak erabiliko ditu barnean, ahal den neurrian, aztarna txikiagoa lortuz.
Emaitzak
Orokorrean, entitateen propietateak JSONB formatuan gordetzeak zure datu-basea diseinatzea eta mantentzea askoz erraztu dezakeela uste dut. Kontsulta asko exekutatzen ari bazara, dena entitatearen taula berean mantentzeak eraginkorrago funtzionatuko du. Eta horrek datuen arteko elkarrekintza errazten duela jada abantaila bat da, baina ondoriozko datu-basea bolumen 3 aldiz txikiagoa da.
Era berean, egindako probetan oinarrituta, errendimendu-galerak oso hutsalak direla ondoriozta dezakegu. Zenbait kasutan, JSONB EAV baino azkarragoa da, are hobea da. Hala ere, erreferente honek, noski, ez ditu alderdi guztiak hartzen (adibidez, propietate-kopuru oso handia duten entitateak, dauden datuen propietate-kopuruaren igoera nabarmena,...), beraz, horiek hobetzeko iradokizunik baduzu. , mesedez utzi lasai iruzkinetan!
Iturria: www.habr.com