{"id":52584,"date":"2019-11-12T00:00:00","date_gmt":"2019-11-11T21:00:00","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blog_prohoster\/zamena-eav-na-jsonb-v-postgresql"},"modified":"2020-02-18T14:00:21","modified_gmt":"2020-02-18T11:00:21","slug":"zamena-eav-na-jsonb-v-postgresql","status":"publish","type":"post","link":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","title":{"rendered":"Zamenjava EAV z JSONB v PostgreSQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<blockquote><p>TL; DR: JSONB lahko znatno poenostavi razvoj sheme Baze podatkov brez vidne izgube zmogljivosti pri poizvedbah.<\/p><\/blockquote>\n<p><\/p>\n<h3>Uvod<\/h3>\n<p>\nOglejmo si klasi\u010den primer, verjetno enega od najstarej\u0161ih na\u010dinov uporabe v svetu relacijskih baz podatkov: imamo entiteto in potrebujemo shraniti dolo\u010dene lastnosti (atribute) te entitete. Vendar pa vsi primerki morda nimajo enakega niza lastnosti, poleg tega pa je v prihodnosti mo\u017eno dodati \u0161e lastnosti.<\/p>\n<p>Najenostavnej\u0161a re\u0161itev tega problema je ustvarjanje stolpca v tabeli baze podatkov za vsako vrednost lastnosti in preprosto izpolnjevanje tistih, ki so potrebne za dolo\u010den primer entitete. Odli\u010dno! Problem je re\u0161en\u2026 do trenutka, ko va\u0161a tabela ne vsebuje milijonov zapisov in ne potrebujete dodati novega zapisa.<\/p>\n<p>Oglejmo si vzorec EAV (<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Entity%E2%80%93attribute%E2%80%93value_model\">Entity-Attribute-Value<\/a><\/noindex>), ki se pojavlja precej pogosto. Ena tabela vsebuje entitete (zapise), druga tabela vsebuje imena lastnosti (atributov), tretja tabela pa povezuje entitete z njihovimi atributi in vsebuje vrednosti teh atributov za trenutno entiteto. To vam omogo\u010da, da imate razli\u010dne nize lastnosti za razli\u010dne objekte ter da dodajate lastnosti \u201cv teku\u201d, ne da bi spreminjali strukturo baze podatkov.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nKljub temu pa te opombe ne bi zapisoval, \u010de ne bi bilo pomanjkljivosti pri uporabi EVA. Na primer, za pridobitev ene ali ve\u010d entitet, ki imajo po 1 atribut, sta potrebna 2 povezavi (join) v poizvedbi: prva \u2013 povezava s tabelo atributov, druga \u2013 povezava s tabelo vrednosti. \u010ce entiteta ima 2 atributa, so potrebne \u017ee 4 povezave! Poleg tega so vsi atributi obi\u010dajno shranjeni v obliki nizov, kar povzro\u010da prenose tipov, tako za rezultat kot tudi za pogoje WHERE. \u010ce pi\u0161ete veliko poizvedb, je to precej potratno z vidika uporabe virov.<\/p>\n<p>Kljub tem o\u010ditnim pomanjkljivostim se EAV \u017ee dolgo uporablja za re\u0161evanje tovrstnih problemov. To so bile neizbe\u017ene pomanjkljivosti, bolj\u0161e alternative pa preprosto ni bilo. <br \/>\nToda nato je v PostgreSQL pri\u0161la nova \u201ctehnologija\u201d...<\/p>\n<p>Za\u010denja od PostgreSQL 9.4 je bil dodan tip podatkov JSONB za shranjevanje binarnih podatkov JSON. \u010ceprav shranjevanje JSON v tej obliki obi\u010dajno zahteva nekoliko ve\u010d prostora in \u010dasa kot preprost besedilni JSON, se operacije z njim izvajajo veliko hitreje. Prav tako JSONB podpira indeksiranje, kar naredi poizvedbe \u0161e hitrej\u0161e.<\/p>\n<p>Tip podatkov JSONB nam omogo\u010da zamenjavo obse\u017enega vzorca EAV z dodajanjem le enega stolpca JSONB v na\u0161o tabelo entitet, kar znatno poenostavi na\u010drtovanje baze podatkov. Mnogi pa trdijo, da bi to moralo biti povezano z zmanj\u0161anjem zmogljivosti ... Zato je ta \u010dlanek nastal.<\/p>\n<h3>Nastavitev testne baze podatkov<\/h3>\n<p>\nZa to primerjavo sem ustvaril bazo podatkov na novi namestitvi PostgreSQL 9.5 na 80-dolarni konfiguraciji <noindex><a rel=\"nofollow\" href=\"https:\/\/www.digitalocean.com\/\">DigitalOcean<\/a><\/noindex> Ubuntu 14.04. Po prilagoditvi nekaterih parametrov v postgresql.conf sem zagnal <noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/coussej\/80c385332ce37df6687f\">ta<\/a><\/noindex> skript z uporabo psql. Za predstavitev podatkov v obliki EAV so bile ustvarjene naslednje tabele:<\/p>\n<pre><code class=\"pgsql\">CREATE TABLE entity ( \n  id           SERIAL PRIMARY KEY, \n  name         TEXT, \n  description  TEXT\n);\nCREATE TABLE entity_attribute (\n  id          SERIAL PRIMARY KEY, \n  name        TEXT\n);\nCREATE TABLE entity_attribute_value (\n  id                  SERIAL PRIMARY KEY, \n  entity_id           INT    REFERENCES entity(id), \n  entity_attribute_id INT    REFERENCES entity_attribute(id), \n  value               TEXT\n);\n<\/code><\/pre>\n<p>\nSpodaj je tabela, kjer bodo shranjeni isti podatki, vendar z atributi v stolpcu tipa JSONB \u2013 <i>properties<\/i>.<\/p>\n<pre><code class=\"pgsql\">CREATE TABLE entity_jsonb (\n  id          SERIAL PRIMARY KEY, \n  name        TEXT, \n  description TEXT,\n  properties  JSONB\n);\n<\/code><\/pre>\n<p>\nIzgleda veliko preprosteje, kajne? Nato je bilo dodanih 10 milijonov zapisov v tabele entitet (<i>entity<\/i> &amp; <i>entity_jsonb<\/i>) in sicer so bile napolnjene enake podatke tabele, kjer se uporablja vzorec EAV in pristop s stolpcem JSONB \u2013 <i>entity_jsonb.properties<\/i>. Tako smo dobili ve\u010d razli\u010dnih tipov podatkov med celotnim sklopom lastnosti. Primer podatkov:<\/p>\n<pre><code class=\"json\">{\n  id:          1\n  name:        \"Entity1\"\n  description: \"Test entiteta \u0161t. 1\"\n  properties:  {\n    color:        \"rde\u010da\"\n    lenght:       120\n    width:        3.1882420\n    hassomething: true\n    country:      \"Belgija\"\n  } \n}<\/code><\/pre>\n<p>\nTorej, zdaj imamo enake podatke za dve mo\u017enosti. Za\u010dnimo primerjati izvedbe v praksi!<\/p>\n<h3>Poenostavitev zasnove<\/h3>\n<p>\n\u017de prej je bilo omenjeno, da je bila zasnova Baze podatkov znatno poenostavljena: ena tabela, zahvaljujo\u010d uporabi stolpca JSONB za lastnosti, namesto uporabe treh tabel za EAV. A kako se to odra\u017ea v poizvedbah? Posodobitev enega lastnosti entitete izgleda takole:<\/p>\n<pre><code class=\"pgsql\">-- EAV\nUPDATE entity_attribute_value \nSET value = 'blue' \nWHERE entity_attribute_id = 1 \n  AND entity_id = 120;\n\n-- JSONB\nUPDATE entity_jsonb \nSET properties = jsonb_set(properties, '{\"color\"}', '\"blue\"') \nWHERE id = 120;\n<\/code><\/pre>\n<p>\nKot vidimo, zadnji poizvedba ne izgleda preproste. Da bi posodobili vrednost lastnosti v JSONB objektu, moramo uporabiti funkcijo <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.5\/static\/functions-json.html\">jsonb_set()<\/a><\/noindex>, in moramo posredovati na\u0161o novo vrednost kot JSONB objekt. Vendar ne potrebujemo poznati nobenega identifikatorja vnaprej. Glede na primer z EAV, moramo poznati tako entity_id kot entity_attribute_id, da izvedemo posodobitev. \u010ce \u017eelite posodobiti lastnost v stolpcu JSONB na podlagi imena objekta, to vse naredimo v eni preprosti vrstici.<\/p>\n<p>Zdaj izberimo tisto entiteto, ki smo jo pravkar posodobili, glede na njen novi barvi:<\/p>\n<pre><code class=\"pgsql\">-- EAV\nSELECT e.name \nFROM entity e \n  INNER JOIN entity_attribute_value eav ON e.id = eav.entity_id\n  INNER JOIN entity_attribute ea ON eav.entity_attribute_id = ea.id\nWHERE ea.name = 'color' AND eav.value = 'blue';\n\n-- JSONB\nSELECT name \nFROM entity_jsonb \nWHERE properties -&gt;&gt; 'color' = 'blue';\n<\/code><\/pre>\n<p>\nMislim, da se lahko strinjamo, da je drugi primer kraj\u0161i (brez join!), in zato bolj berljiv. Tukaj zmaga JSONB! Uporabljamo operator JSON -&gt;&gt; za pridobitev barve kot besedilne vrednosti iz JSONB objekta. Obstaja tudi drugi na\u010din dosego istega rezultata v JSONB modelu z uporabo operatorja @&gt;:<\/p>\n<pre><code class=\"pgsql\">-- JSONB \nSELECT name \nFROM entity_jsonb \nWHERE properties @&gt; '{\"color\": \"blue\"}';\n<\/code><\/pre>\n<p>\nTo je nekoliko zahtevnej\u0161e: preverjamo, ali JSON objekt v stolpcu lastnosti vsebuje objekt, ki se nahaja desno od operatorja @&gt;. Manj berljivo, bolj zmogljivo (glej naprej). <\/p>\n<p>Pojdimo \u0161e korak naprej in poenostavimo uporabo JSONB, ko morate izbrati ve\u010d lastnosti hkrati. Tukaj resni\u010dno pristoji JSONB pristop: preprosto izberemo lastnosti kot dodatne stolpce v na\u0161em naboru rezultatov brez potrebe po zdru\u017eevanju:<\/p>\n<pre><code class=\"pgsql\">-- JSONB \nSELECT name\n  , properties -&gt;&gt; 'color'\n  , properties -&gt;&gt; 'country'\nFROM entity_jsonb \nWHERE id = 120;\n<\/code><\/pre>\n<p>\nPri EAV boste potrebovali 2 zdru\u017eitvi za vsako lastnost, ki jo \u017eelite povpra\u0161ati. Po mojem mnenju zgoraj navedene poizvedbe ka\u017eejo veliko poenostavitev pri oblikovanju baze podatkov. Ve\u010d primerov, kako pisati poizvedbe za JSONB, morda tudi v <noindex><a rel=\"nofollow\" href=\"http:\/\/schinckel.net\/2014\/05\/25\/querying-json-in-postgres\/\">ovom<\/a><\/noindex> objavi.<br \/>\nSedaj je \u010das, da govorimo o zmogljivosti.<\/p>\n<h3>Performansa<\/h3>\n<p>\nDa bi primerjal zmogljivost, sem uporabil <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/sql-explain.html\">EXPLAIN ANALYZE<\/a><\/noindex> v poizvedbah, za \u0161tetje \u010dasa izvajanja. Vsaka poizvedba je bila izvedena vsaj trikrat, ker prvi\u010d na\u010drtovalcu poizvedb vzame ve\u010d \u010dasa. Najprej sem izvedel poizvedbe brez kakr\u0161nih koli indeksov. O\u010ditno je to koristilo JSONB, saj joini, potrebni za EAV, niso mogli uporabljati indeksov (polja tujih klju\u010dev niso bila indeksirana). Po tem sem ustvaril indeks za 2 stolpca tujih klju\u010dev v tabeli vrednosti EAV, poleg tega indeks <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/textsearch-indexes.html\">GIN<\/a><\/noindex> za stolpec JSONB.<\/p>\n<p>Posodobitve podatkov so pokazale naslednje rezultate glede \u010dasa (v ms). Upo\u0161tevajte, da je lestvica logaritmi\u010dna:<\/p>\n<p><img decoding=\"async\" alt=\"Zamenjava EAV z JSONB v PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/8a12ccd7a46d04868b1cc5fcaf01a581.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nVidimo, da je JSONB veliko (&gt; 50000-krat) hitrej\u0161i od EAV, \u010de ne uporabljamo indeksov, zaradi razloga, omenjenega zgoraj. Ko indeksiramo stolpce s primarnimi klju\u010di, skoraj izgine razlika, vendar je JSONB \u0161e vedno 1,3-krat hitrej\u0161i od EAV. Upo\u0161tevajte, da indeks v stolpcu JSONB tukaj nima nobenega vpliva, saj ne uporabljamo stolpca lastnosti v kriterijih ocenjevanja. <\/p>\n<p>Za izbiro podatkov na podlagi vrednosti lastnosti dobimo naslednje rezultate (navadna lestvica):<\/p>\n<p><img decoding=\"async\" alt=\"Zamenjava EAV z JSONB v PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/e9a1fd797ef60132e661da686f6214a3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOpaziti je, da JSONB ponovno deluje hitreje kot EAV brez indeksov, vendar ko je EAV z indeksi \u2013 vseeno deluje hitreje kot JSONB. Kasneje sem opazil, da je \u010das za poizvedbe JSONB enak, kar me je pripeljalo do spoznanja, da GIN-indeks ne deluje. O\u010ditno, ko uporabljate indeks GIN za stolpec s polnimi lastnostmi, deluje le pri uporabi operatorja vklju\u010ditve @&gt;. To sem uporabil v novem testu, kar je imelo ogromen vpliv na \u010das: le 0,153 ms! To je 15000-krat hitreje kot EAV in 25000-krat hitreje kot operator -&gt;&gt;. <\/p>\n<p>Mislim, da je bilo dovolj hitro!<\/p>\n<h3>Velikost tabel BDP<\/h3>\n<p>\nPoglejmo velikosti tabel pri obeh pristopih. V psql lahko prika\u017eemo velikost vseh tabel in indeksov s pomo\u010djo ukaza <b>dti+<\/b><\/p>\n<p><img decoding=\"async\" alt=\"Zamenjava EAV z JSONB v PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/c6c1fe7901fe9ae2bd446cf4ae99b923.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nZa pristop EAV zna\u0161ajo velikosti tabel pribli\u017eno 3068 MB, indeksi pa do 3427 MB, kar skupaj daje 6,43 GB. Pri uporabi pristopa z JSONB se uporablja 1817 MB za tabelo in 318 MB za indekse, kar zna\u0161a 2,08 GB. Izka\u017ee se, da je 3-krat manj! Ta podatek me je malo presenetil, ker shranjujemo imena lastnosti v vsakem objektu JSONB. <\/p>\n<p>Toda, vendar \u0161tevilke govorijo same zase: v EAV hranimo 2 celotna zunanja klju\u010da za vrednost atributa, kar pomeni 8 bajtov dodatnih podatkov. Poleg tega v EAV vse vrednosti lastnosti hranimo v besedilu, medtem ko JSONB uporablja numeri\u010dne in logi\u010dne vrednosti, kjer je to mogo\u010de, kar pripomore k manj\u0161emu obsegu.<\/p>\n<h3>Zaklju\u010dki<\/h3>\n<p>\nNa splo\u0161no menim, da lahko hranjenje lastnosti entitet v formatu JSONB znatno poenostavi na\u010drtovanje in vzdr\u017eevanje va\u0161e baze podatkov. \u010ce izvajate veliko poizvedb, bo vse, kar je shranjeno v eni tabeli z entiteto, resni\u010dno delovalo bolj u\u010dinkovito. Dejansko poenostavitev interakcije med podatki je \u017ee prednost, toda tudi rezultatna baza podatkov je 3-krat manj\u0161a.<\/p>\n<p>Prav tako, na podlagi opravljenih testov, lahko zaklju\u010dimo, da so izgube zmogljivosti zelo neznatne. V nekaterih primerih JSONB deluje celo hitreje kot EAV, kar ga dela \u0161e bolj\u0161o izbiro. Vendar pa ta referen\u010dni test seveda ne pokriva vseh vidikov (na primer, entitete z zelo veliko lastnosti, znatno pove\u010danjem \u0161tevila lastnosti obstoje\u010dih podatkov,\u2026), zato, \u010de imate kak\u0161ne predloge, kako jih izbolj\u0161ati, jih prosim pustite v komentarjih!<br \/>\n<br \/>Izvor: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/475178\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>TL; DR: JSONB \u043c\u043e\u0436\u0435\u0442 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0441\u0445\u0435\u043c\u044b \u0411\u0414 \u0431\u0435\u0437 \u0443\u0449\u0435\u0440\u0431\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445. \u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u041f\u0440\u0438\u0432\u0435\u0434\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435, \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0441\u0442\u0430\u0440\u0435\u0439\u0448\u0438\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043c\u0438\u0440\u0435 \u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0411\u0414 (\u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445): \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c, \u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 (\u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b) \u044d\u0442\u043e\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438. \u041d\u043e \u043d\u0435 \u0432\u0441\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u044b \u043c\u043e\u0433\u0443\u0442 \u0438\u043c\u0435\u044e\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0441\u0432\u043e\u0439\u0441\u0442\u0432, \u043a \u0442\u043e\u043c\u0443 \u0436\u0435 \u0432 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-52584","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.4 - aioseo.com -->\n\t<meta name=\"description\" content=\"TL; DR: JSONB \u043c\u043e\u0436\u0435\u0442 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0441\u0445\u0435\u043c\u044b \u0411\u0414 \u0431\u0435\u0437 \u0443\u0449\u0435\u0440\u0431\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445. \u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u041f\u0440\u0438\u0432\u0435\u0434\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435, \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0441\u0442\u0430\u0440\u0435\u0439\u0448\u0438\u0445.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"sl_SI\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0417\u0430\u043c\u0435\u043d\u0430 EAV \u043d\u0430 JSONB \u0432 PostgreSQL | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"TL; DR: JSONB \u043c\u043e\u0436\u0435\u0442 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0441\u0445\u0435\u043c\u044b \u0411\u0414 \u0431\u0435\u0437 \u0443\u0449\u0435\u0440\u0431\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445. \u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u041f\u0440\u0438\u0432\u0435\u0434\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435, \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0441\u0442\u0430\u0440\u0435\u0439\u0448\u0438\u0445.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-11-11T21:00:00+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-02-18T11:00:21+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Zamenjava EAV z JSONB v PostgreSQL | ProHoster","description":"TL; DR: JSONB lahko znatno poenostavi razvoj sheme baze podatkov brez \u017ertvovanja zmogljivosti poizvedb. Uvod Uvedimo klasi\u010den primer, verjetno enega od najstarej\u0161ih.","canonical_url":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sl_SI","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0417\u0430\u043c\u0435\u043d\u0430 EAV \u043d\u0430 JSONB \u0432 PostgreSQL | ProHoster","og:description":"TL; DR: JSONB \u043c\u043e\u0436\u0435\u0442 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0441\u0445\u0435\u043c\u044b \u0411\u0414 \u0431\u0435\u0437 \u0443\u0449\u0435\u0440\u0431\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445. \u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u041f\u0440\u0438\u0432\u0435\u0434\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435, \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0441\u0442\u0430\u0440\u0435\u0439\u0448\u0438\u0445.","og:url":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-11-11T21:00:00+00:00","article:modified_time":"2020-02-18T11:00:21+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"52584","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-24 04:07:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 20:40:27","updated":"2026-01-24 04:07:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts\/52584","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/comments?post=52584"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts\/52584\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/media?parent=52584"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/categories?post=52584"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/tags?post=52584"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}