Tissostitwixxi EAV b'JSONB f'PostgreSQL

TL; DR: JSONB jista 'jissimplifika ħafna l-iżvilupp ta' skema tad-database mingħajr ma jissagrifikaw il-prestazzjoni tal-mistoqsija.

Introduzzjoni

Ejja nagħtu eżempju klassiku ta 'probabbilment wieħed mill-eqdem każijiet ta' użu fid-dinja ta 'database relazzjonali (database): għandna entità, u għandna bżonn insalvaw ċerti proprjetajiet (attributi) ta' din l-entità. Iżda mhux l-istanzi kollha jista 'jkollhom l-istess sett ta' proprjetajiet, u aktar proprjetajiet jistgħu jiġu miżjuda fil-futur.

L-eħfef mod biex issolvi din il-problema huwa li toħloq kolonna fit-tabella tad-database għal kull valur tal-proprjetà, u sempliċement imla dawk li huma meħtieġa għal istanza speċifika ta 'entità. Kbir! Problema solvuta... sakemm it-tabella tiegħek fiha miljuni ta' rekords u trid iżżid rekord ġdid.

Ikkunsidra l-mudell EAV (Entità-Attribut-Valur), iseħħ spiss. Tabella waħda fiha entitajiet (rekords), tabella oħra fiha ismijiet ta’ proprjetà (attributi), u t-tielet tabella tassoċja entitajiet mal-attributi tagħhom u fiha l-valur ta’ dawk l-attributi għall-entità kurrenti. Dan jagħtik l-abbiltà li jkollok settijiet differenti ta 'proprjetajiet għal oġġetti differenti, u żżid ukoll proprjetajiet fuq il-fly mingħajr ma tbiddel l-istruttura tad-database.

Madankollu, ma nkunx nikteb din il-kariga kieku ma kienx hemm xi aspetti negattivi għall-approċċ EVA. Allura, pereżempju, biex tinkiseb entità waħda jew aktar li għandhom attribut 1 kull waħda, 2 join huma meħtieġa fil-mistoqsija: l-ewwel huwa join mat-tabella tal-attributi, it-tieni huwa join mat-tabella tal-valuri. Jekk entità għandha 2 attributi, allura 4 join huma meħtieġa! Barra minn hekk, l-attributi kollha huma tipikament maħżuna bħala kordi, li jirriżulta f'ikkastjar tat-tip kemm għar-riżultat kif ukoll għall-klawżola WHERE. Jekk tikteb ħafna mistoqsijiet, allura dan huwa pjuttost ħela f'termini ta 'użu tar-riżorsi.

Minkejja dawn in-nuqqasijiet ovvji, l-EAV ilha tintuża biex issolvi dawn it-tipi ta 'problemi. Dawn kienu nuqqasijiet inevitabbli, u sempliċement ma kien hemm l-ebda alternattiva aħjar.
Imma mbagħad dehret "teknoloġija" ġdida f'PostgreSQL...

Nibda b'PostgreSQL 9.4, it-tip ta 'dejta JSONB ġie miżjud biex jaħżen id-dejta binarja JSON. Għalkemm il-ħażna ta 'JSON f'dan il-format tipikament tieħu ftit aktar spazju u ħin minn JSON b'test sempliċi, it-twettiq ta' operazzjonijiet fuqu huwa ħafna aktar mgħaġġel. JSONB jappoġġja wkoll l-indiċjar, li jagħmel il-mistoqsijiet saħansitra aktar mgħaġġel.

It-tip tad-dejta JSONB jippermettilna nissostitwixxu l-mudell EAV ingombranti billi nżidu kolonna JSONB waħda biss mat-tabella tal-entità tagħna, u tissimplifika bil-kbir id-disinn tad-database. Iżda ħafna jargumentaw li dan għandu jkun akkumpanjat minn tnaqqis fil-produttività... Huwa għalhekk li ktibt dan l-artiklu.

Twaqqif ta' database tat-test

Għal dan il-paragun, ħloqt id-database fuq installazzjoni ġdida ta 'PostgreSQL 9.5 fuq il-bini ta' $80 DigitalOcean Ubuntu 14.04 Wara li kkonfigurajt xi parametri f'postgresql.conf, ħaddemt dan skript li juża psql. It-tabelli li ġejjin inħolqu biex tiġi ppreżentata d-dejta f'forma EAV:

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

Hawn taħt hawn tabella fejn se tinħażen l-istess data, iżda b'attributi f'kolonna tat-tip JSONB - proprjetajiet.

CREATE TABLE entity_jsonb (
  id          SERIAL PRIMARY KEY, 
  name        TEXT, 
  description TEXT,
  properties  JSONB
);

Jidher ħafna aktar sempliċi, hux? Imbagħad ġie miżjud mat-tabelli tal-entitajiet (entità & entità_jsonb) 10 miljun rekord, u għaldaqstant, it-tabella kienet mimlija bl-istess data bl-użu tal-mudell EAV u l-approċċ b'kolonna JSONB - entity_jsonb.properties. Għalhekk, irċevejna diversi tipi ta 'dejta differenti fost is-sett kollu ta' proprjetajiet. Dejta ta' eżempju:

{
  id:          1
  name:        "Entity1"
  description: "Test entity no. 1"
  properties:  {
    color:        "red"
    lenght:       120
    width:        3.1882420
    hassomething: true
    country:      "Belgium"
  } 
}

Allura issa għandna l-istess data għaż-żewġ għażliet. Ejja nibdew inqabblu l-implimentazzjonijiet fuq ix-xogħol!

Issimplifika d-disinn tiegħek

Preċedentement kien iddikjarat li d-disinn tad-database kien issimplifikat ħafna: tabella waħda, billi tuża kolonna JSONB għall-proprjetajiet, minflok tuża tliet tabelli għal EAV. Imma dan kif huwa rifless fit-talbiet? L-aġġornament ta' proprjetà ta' entità waħda jidher bħal dan:

-- 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;

Kif tistgħu taraw, l-aħħar talba ma tidhirx aktar sempliċi. Biex taġġorna l-valur ta 'proprjetà f'oġġett JSONB irridu nużaw il-funzjoni jsonb_set(), u għandha tgħaddi l-valur il-ġdid tagħna bħala oġġett JSONB. Madankollu, m'għandniex bżonn inkunu nafu l-ebda identifikatur minn qabel. Meta nħarsu lejn l-eżempju EAV, irridu nkunu nafu kemm l-entity_id kif ukoll l-entity_attribute_id sabiex inwettqu l-aġġornament. Jekk trid taġġorna proprjetà f'kolonna JSONB ibbażata fuq l-isem tal-oġġett, allura dan kollu jsir f'linja waħda sempliċi.

Issa ejja nagħżlu l-entità li għadna kemm aġġornajna abbażi tal-kulur il-ġdid tagħha:

-- 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';

Naħseb li nistgħu naqblu li t-tieni waħda hija iqsar (no join!), u għalhekk aktar tinqara. JSONB jirbaħ hawn! Aħna nużaw l-operatur JSON ->> biex niksbu l-kulur bħala valur tat-test mill-oġġett JSONB. Hemm ukoll it-tieni mod biex jinkiseb l-istess riżultat fil-mudell JSONB billi tuża l-operatur @>:

-- JSONB 
SELECT name 
FROM entity_jsonb 
WHERE properties @> '{"color": "blue"}';

Dan huwa ftit aktar ikkumplikat: niċċekkjaw biex naraw jekk l-oġġett JSON fil-kolonna tal-proprjetajiet tiegħu fihx oġġett li jinsab fuq il-lemin tal-operatur @>. Inqas jinqara, aktar produttiv (ara hawn taħt).

Ejja nagħmlu l-użu ta' JSONB saħansitra aktar faċli meta jkollok bżonn tagħżel proprjetajiet multipli f'daqqa. Dan huwa fejn l-approċċ JSONB verament jidħol: aħna sempliċiment nagħżlu proprjetajiet bħala kolonni addizzjonali fis-sett tar-riżultati tagħna mingħajr il-ħtieġa ta 'joints:

-- JSONB 
SELECT name
  , properties ->> 'color'
  , properties ->> 'country'
FROM entity_jsonb 
WHERE id = 120;

B'EAV ser ikollok bżonn 2 join għal kull proprjetà li trid tagħmel mistoqsija. Fl-opinjoni tiegħi, il-mistoqsijiet ta 'hawn fuq juru simplifikazzjoni kbira fid-disinn tad-database. Ara aktar eżempji ta’ kif tikteb mistoqsijiet JSONB, ukoll fi dan post.
Issa wasal iż-żmien li nitkellmu dwar il-prestazzjoni.

Produttività

Biex tqabbel il-prestazzjoni użajt SPJEGA ANALIZZA fil-mistoqsijiet, biex jiġi kkalkulat il-ħin tal-eżekuzzjoni. Kull mistoqsija ġiet esegwita mill-inqas tliet darbiet minħabba li l-pjanifikatur tal-mistoqsija jieħu aktar żmien l-ewwel darba. L-ewwel għamilt il-mistoqsijiet mingħajr ebda indiċi. Ovvjament, dan kien vantaġġ ta 'JSONB, peress li l-joints meħtieġa għal EAV ma setgħux jużaw indiċi (oqsma ewlenin barranin ma kinux indiċjati). Wara dan ħloqt indiċi fuq iż-żewġ kolonni ewlenin barranin tat-tabella tal-valur EAV, kif ukoll indiċi GIN għal kolonna JSONB.

L-aġġornament tad-dejta wera r-riżultati li ġejjin f'termini ta 'żmien (f'ms). Innota li l-iskala hija logaritmika:

Tissostitwixxi EAV b'JSONB f'PostgreSQL

Naraw li JSONB huwa ħafna (> 50000-x) aktar mgħaġġel minn EAV jekk ma tużax indiċi, għar-raġuni ddikjarata hawn fuq. Meta aħna indiċi kolonni b'ċwievet primarji, id-differenza kważi tisparixxi, iżda JSONB għadu 1,3 darbiet aktar mgħaġġel minn EAV. Innota li l-indiċi fuq il-kolonna JSONB m'għandu l-ebda effett hawnhekk peress li aħna mhux qed nużaw il-kolonna tal-proprjetà fil-kriterji ta 'evalwazzjoni.

Għall-għażla tad-dejta bbażata fuq il-valur tal-proprjetà, irridu nġibu r-riżultati li ġejjin (skala normali):

Tissostitwixxi EAV b'JSONB f'PostgreSQL

Tista 'tinnota li JSONB jerġa' jaħdem aktar malajr minn EAV mingħajr indiċi, iżda meta EAV b'indiċi, xorta jaħdem aktar malajr minn JSONB. Imma mbagħad rajt li l-ħinijiet għall-mistoqsijiet JSONB kienu l-istess, dan wassalni għall-fatt li l-indiċi GIN ma jaħdmux. Apparentement meta tuża indiċi GIN fuq kolonna bi proprjetajiet popolati, dan jidħol fis-seħħ biss meta tuża l-operatur include @>. Użajt dan f'test ġdid u kellu impatt kbir fuq il-ħin: 0,153ms biss! Dan huwa 15000 darba aktar mgħaġġel mill-EAV u 25000 darba aktar mgħaġġel mill-operatur ->>.

Naħseb li kien mgħaġġel biżżejjed!

Daqs tat-tabella tad-database

Ejja nqabblu d-daqsijiet tat-tabella għaż-żewġ approċċi. F'psql nistgħu nuru d-daqs tat-tabelli u l-indiċi kollha bl-użu tal-kmand dti+

Tissostitwixxi EAV b'JSONB f'PostgreSQL

Għall-approċċ EAV, id-daqsijiet tal-mejda huma madwar 3068 MB u indiċi sa 3427 MB għal total ta '6,43 GB. L-approċċ JSONB juża 1817 MB għat-tabella u 318 MB għall-indiċi, li huwa 2,08 GB. Jirriżulta 3 darbiet inqas! Dan il-fatt sorpriżani ftit għaliex aħna naħżnu l-ismijiet tal-proprjetà f'kull oġġett JSONB.

Iżda xorta waħda, in-numri jitkellmu waħedhom: f'EAV aħna naħżnu ċwievet barranin 2 interi għal kull valur ta 'attribut, li jirriżultaw fi 8 bytes ta' data addizzjonali. Barra minn hekk, EAV jaħżen il-valuri tal-proprjetà kollha bħala test, filwaqt li JSONB se juża valuri numeriċi u booleani internament fejn possibbli, u dan jirriżulta f'impronta iżgħar.

Riżultati ta '

B'mod ġenerali, naħseb li l-iffrankar tal-proprjetajiet tal-entità fil-format JSONB jista 'jagħmel id-disinn u ż-żamma tad-database tiegħek ħafna aktar faċli. Jekk qed tmexxi ħafna mistoqsijiet, imbagħad iżżomm kollox fl-istess tabella bħall-entità fil-fatt taħdem b'mod aktar effiċjenti. U l-fatt li dan jissimplifika l-interazzjoni bejn id-dejta diġà huwa vantaġġ, iżda d-database li tirriżulta hija 3 darbiet iżgħar fil-volum.

Ukoll, abbażi tat-testijiet imwettqa, nistgħu nikkonkludu li t-telf fil-prestazzjoni huwa insinifikanti ħafna. F'xi każijiet, JSONB huwa saħansitra aktar mgħaġġel minn EAV, u jagħmilha saħansitra aħjar. Madankollu, dan il-punt ta’ referenza ovvjament ma jkoprix l-aspetti kollha (eż. entitajiet b’numru kbir ħafna ta’ proprjetajiet, żieda sinifikanti fin-numru ta’ proprjetajiet ta’ data eżistenti,...), allura jekk għandek xi suġġerimenti dwar kif ittejjebhom , jekk jogħġbok tħossok liberu li tħalli fil-kummenti!

Sors: www.habr.com

Ixtri hosting affidabbli għal siti bi protezzjoni DDoS, servers VPS VDS 🔥 Ixtri hosting ta' websajts affidabbli bi protezzjoni DDoS, servers VPS VDS | ProHoster