{"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\/hr\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","title":{"rendered":"Zamjena EAV-a s JSONB-om u PostgreSQL-u","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<blockquote><p>TL; DR: JSONB mo\u017ee zna\u010dajno pojednostaviti razvoj sheme baze podataka bez gubitka performansi u upitima.<\/p><\/blockquote>\n<p><\/p>\n<h3>Uvod<\/h3>\n<p>\nUzmimo klasi\u010dan primjer, vjerojatno jedan od najstarijih na\u010dina kori\u0161tenja u svijetu relacijskih baza podataka: imamo entitet i potrebno je pohraniti odre\u0111ena svojstva (atribute) tog entiteta. No, ne mogu svi primjeri imati isti skup svojstava, a mogu\u0107e je i dodavanje novih svojstava u budu\u0107nosti.<\/p>\n<p>Najjednostavniji na\u010din rje\u0161avanja ovog problema je stvaranje stupca u tablici baze podataka za svaku vrijednost svojstva i jednostavno popunjavanje onih koje su potrebne za odre\u0111eni primjer entiteta. Odli\u010dno! Problem rije\u0161en\u2026 sve dok va\u0161a tablica ne sadr\u017ei milijune zapisa i ne dobijete potrebu za dodavanjem novog zapisa.<\/p>\n<p>Razmotrite obrazac EAV (<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Entity%E2%80%93attribute%E2%80%93value_model\">Entity-Attribute-Value<\/a><\/noindex>), koji se \u010desto koristi. Jedna tablica sadr\u017ei entitete (zapise), druga tablica sadr\u017ei imena svojstava (atributa), a tre\u0107a tablica povezuje entitete s njihovim atributima i sadr\u017ei vrijednost tih atributa za trenutni entitet. To vam omogu\u0107uje da imate razli\u010dite skupove svojstava za razli\u010dite objekte, kao i dodavanje svojstava \u201cu letu\u201d, bez promjene strukture baze podataka.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nIpak, ne bih pisao ovu zabilje\u0161ku da nije bilo nedostataka u pristupu kori\u0161tenju EVA. Na primjer, za dobivanje jedne ili vi\u0161e entiteta koji imaju 1 atribut potrebno je 2 spoja u upitu: prvi \u2013 spoj s tabelom atributa, drugi \u2013 spoj s tabelom vrijednosti. Ako entitet ima 2 atributa, potrebno je ve\u0107 4 spoja! Osim toga, svi atributi obi\u010dno se \u010duvaju u obliku stringova, \u0161to dovodi do konverzije tipova, kako za rezultat, tako i za uvjet WHERE. Ako pi\u0161ete mnogo upita, to je prili\u010dno rasipno s aspekta kori\u0161tenja resursa.<\/p>\n<p>Unato\u010d ovim o\u010ditim nedostacima, EAV se ve\u0107 dugo koristi za rje\u0161avanje ovakvih problema. To su bili neizbje\u017eni nedostaci, a bolja alternativa jednostavno nije postojala. <br \/>\nAli tada je u PostgreSQL-u do\u0161la nova \u201ctehnologija\u201d...<\/p>\n<p>Od PostgreSQL 9.4, uveden je tip podatka JSONB za pohranu binarnih JSON podataka. Iako pohrana JSON-a u ovom formatu obi\u010dno traje malo du\u017ee i zauzima vi\u0161e prostora nego obi\u010dan tekstualni JSON, izvo\u0111enje operacija s njim je mnogo br\u017ee. Tako\u0111er, JSONB podr\u017eava indeksiranje, \u0161to dodatno ubrzava upite.<\/p>\n<p>Tip podatka JSONB omogu\u0107uje nam da zamijenimo glomazni obrazac EAV dodavanjem samo jedne JSONB kolone u na\u0161u tablicu entiteta, \u0161to znatno pojednostavljuje dizajn baze podataka. Me\u0111utim, mnogi tvrde da bi to trebalo dovesti do smanjenja performansi\u2026 Upravo iz tog razloga i nastaje ovaj \u010dlanak.<\/p>\n<h3>Postavljanje testne baze podataka<\/h3>\n<p>\nZa ovu usporedbu, stvorio sam bazu podataka na novoj instalaciji PostgreSQL 9.5 na 80-dolarskoj konfiguraciji <noindex><a rel=\"nofollow\" href=\"https:\/\/www.digitalocean.com\/\">DigitalOcean<\/a><\/noindex> Ubuntu 14.04. Nakon postavljanja nekih parametara u postgresql.conf, pokrenuo sam <noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/coussej\/80c385332ce37df6687f\">ovaj<\/a><\/noindex> skriptu pomo\u0107u psql-a. Za predstavljanje podataka u obliku EAV kreirane su sljede\u0107e tablice:<\/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>\nU nastavku je prikazana tablica gdje \u0107e biti pohranjeni isti podaci, ali s atributima u koloni 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 puno jednostavnije, zar ne? Zatim je u tablice entiteta (<i>entity<\/i> &amp; <i>entity_jsonb<\/i>) dodano 10 milijuna zapisa, i tako su ispunjeni identi\u010dnim podacima tablice gdje se koristi EAV obrazac i pristup s JSONB kolonom \u2013 <i>entity_jsonb.properties<\/i>. Tako smo dobili nekoliko razli\u010ditih tipova podataka me\u0111u svim skupovima svojstava. Primjer podataka:<\/p>\n<pre><code class=\"json\">{\n  id:          1\n  name:        \"Entity1\"\n  description: \"Testni entitet br. 1\"\n  properties:  {\n    color:        \"crvena\"\n    lenght:       120\n    width:        3.1882420\n    hassomething: true\n    country:      \"Belgija\"\n  } \n}<\/code><\/pre>\n<p>\nDakle, sada imamo iste podatke za dvije varijante. Po\u010dnimo uspore\u0111ivati implementacije u radu!<\/p>\n<h3>Pojednostavljenje dizajna<\/h3>\n<p>\nVe\u0107 je re\u010deno da je dizajn baze podataka znatno pojednostavljen: jedna tablica, kori\u0161tenjem JSONB kolone za svojstva, umjesto kori\u0161tenja tri tablice za EAV. No, kako to utje\u010de na upite? A\u017euriranje jednog svojstva entiteta izgleda ovako:<\/p>\n<pre><code class=\"pgsql\">-- EAV\nUPDATE entity_attribute_value \nSET value = 'plava' \nWHERE entity_attribute_id = 1 \n  AND entity_id = 120;\n\n-- JSONB\nUPDATE entity_jsonb \nSET properties = jsonb_set(properties, '{\"color\"}', '\"plava\"') \nWHERE id = 120;\n<\/code><\/pre>\n<p>\nKao \u0161to vidimo, posljednji upit ne izgleda jednostavnije. Da bismo a\u017eurirali vrijednost svojstva u JSONB objektu, moramo koristiti funkciju <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.5\/static\/functions-json.html\">jsonb_set()<\/a><\/noindex>, i moramo proslijediti na\u0161u novu vrijednost kao JSONB objekt. Me\u0111utim, ne trebamo unaprijed znati nijedan identifikator. Gledaju\u0107i primjer s EAV, trebamo znati i entity_id i entity_attribute_id da bismo izvr\u0161ili a\u017euriranje. Ako \u017eelite a\u017eurirati svojstvo u JSONB stupcu na temelju naziva objekta, - to se sve radi jednom jednostavnom linijom.<\/p>\n<p>Sada, odaberimo entitet koji smo upravo a\u017eurirali prema uvjetu njegove nove boje:<\/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 = 'plava';\n\n-- JSONB\nSELECT name \nFROM entity_jsonb \nWHERE properties -&gt;&gt; 'color' = 'plava';\n<\/code><\/pre>\n<p>\nMislim da se mo\u017eemo slo\u017eiti da je druga opcija kra\u0107a (bez join!), a time i \u010ditljivija. Ovdje JSONB pobje\u0111uje! Koristimo operator JSON -&gt;&gt; da dobijemo boju kao tekstualnu vrijednost iz JSONB objekta. Postoji i drugi na\u010din postizanja istog rezultata u JSONB modelu koriste\u0107i operator @&gt;:<\/p>\n<pre><code class=\"pgsql\">-- JSONB \nSELECT name \nFROM entity_jsonb \nWHERE properties @&gt; '{\"color\": \"plava\"}';\n<\/code><\/pre>\n<p>\nTo je malo slo\u017eenije: provjeravamo sadr\u017ei li JSON objekt u stupcu svojstava objekt koji se nalazi desno od operatora @&gt;. Manje \u010ditljivo, ali u\u010dinkovitije (vidi dalje). <\/p>\n<p>Dopustite da jo\u0161 vi\u0161e pojednostavimo kori\u0161tenje JSONB kada trebate odabrati vi\u0161e svojstava istovremeno. Tada se JSONB pristup stvarno isplati: jednostavno odabiremo svojstva kao dodatne stupce u na\u0161im skupovima rezultata bez potrebe za spajanjima:<\/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>\nS EAV trebate 2 spoja za svako svojstvo koje \u017eelite zatra\u017eiti. Po mom mi\u0161ljenju, gornji upiti pokazuju zna\u010dajno pojednostavljenje dizajna baze podataka. Vi\u0161e primjera kako pisati upite za JSONB tako\u0111er mo\u017ee se na\u0107i u <noindex><a rel=\"nofollow\" href=\"http:\/\/schinckel.net\/2014\/05\/25\/querying-json-in-postgres\/\">ovom<\/a><\/noindex> postu.<br \/>\nSada je do\u0161lo vrijeme da razgovaramo o performansama.<\/p>\n<h3>Performanse<\/h3>\n<p>\nKako bismo usporedili performanse, koristio sam <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/sql-explain.html\">EXPLAIN ANALYZE<\/a><\/noindex> u upitima, za mjerenje vremena izvr\u0161avanja. Svaki upit izvr\u0161en je najmanje tri puta, jer planneru upita treba vi\u0161e vremena prvi put. Prvo sam izvr\u0161io upite bez ikakvih indeksa. O\u010digledno, to je bilo korisno za JSONB, jer se join potrebni za EAV nisu mogli koristiti indekse (polja stranih klju\u010deva nisu bila indeksirana). Nakon toga sam stvorio indeks za 2 kolone stranih klju\u010deva u EAV tablici vrijednosti, kao i indeks <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/textsearch-indexes.html\">GIN<\/a><\/noindex> za kolonu JSONB.<\/p>\n<p>A\u017euriranja podataka pokazala su sljede\u0107e rezultate prema vremenu (u ms). Obavite pa\u017enju da je skala logaritamska:<\/p>\n<p><img decoding=\"async\" alt=\"Zamjena EAV-a s JSONB-om u PostgreSQL-u\" src=\"\/wp-content\/uploads\/2019\/11\/8a12ccd7a46d04868b1cc5fcaf01a581.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nVidimo da je JSONB mnogo (&gt; 50000-x) br\u017ei od EAV, ako ne koristimo indekse, iz razloga navedenog iznad. Kada indeksiramo kolone s primarnim klju\u010devima, razlika gotovo nestaje, ali JSONB je jo\u0161 uvijek 1,3 puta br\u017ei od EAV. Obavite pa\u017enju da indeks u koloni JSONB ovdje nema nikakvog utjecaja, jer ne koristimo kolonu svojstava u kriterijima ocjene. <\/p>\n<p>Za odabir podataka na temelju vrijednosti svojstva dobivamo sljede\u0107e rezultate (normalna skala):<\/p>\n<p><img decoding=\"async\" alt=\"Zamjena EAV-a s JSONB-om u PostgreSQL-u\" src=\"\/wp-content\/uploads\/2019\/11\/e9a1fd797ef60132e661da686f6214a3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMo\u017ee se primijetiti da JSONB ponovno radi br\u017ee od EAV bez indeksa, ali kada je EAV s indeksima \u2013 on ipak radi br\u017ee od JSONB. No, kasnije sam primijetio da su vremena za JSONB upite bila jednaka, \u0161to me navelo na pomisao da GIN-indeks ne funkcionira. O\u010digledno, kada koristite GIN indeks za kolonu sa ispunjenim svojstvima, on djeluje samo kada koristite operator uklju\u010divanja @&gt;. Koristio sam to u novom testu, \u0161to je imalo ogroman utjecaj na vrijeme: samo 0,153 ms! To je 15000 puta br\u017ee od EAV, i 25000 puta br\u017ee od operatora -&gt;&gt;. <\/p>\n<p>Mislim da je to bilo dovoljno brzo!<\/p>\n<h3>Veli\u010dina BD tablica<\/h3>\n<p>\nUsporedimo veli\u010dine tablica kod oba pristupa. U psql-u mo\u017eemo prikazati veli\u010dinu svih tablica i indeksa pomo\u0107u naredbe <b>dti+<\/b><\/p>\n<p><img decoding=\"async\" alt=\"Zamjena EAV-a s JSONB-om u PostgreSQL-u\" src=\"\/wp-content\/uploads\/2019\/11\/c6c1fe7901fe9ae2bd446cf4ae99b923.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nZa pristup EAV veli\u010dine tablica iznose pribli\u017eno 3068 MB, a indeksi do 3427 MB, \u0161to ukupno iznosi 6,43 GB. Kada koristimo pristup s JSONB-om koristi se 1817 MB za tablicu i 318 MB za indekse, \u0161to iznosi 2,08 GB. Dakle, tri puta manje! Ova \u010dinjenica me malo iznenadila, jer pohranjujemo imena svojstava u svakom JSONB objektu. <\/p>\n<p>Me\u0111utim, brojke same govore: u EAV \u010duvamo 2 cijela vanjska klju\u010da za vrijednost atributa, \u0161to rezultira dodatnih 8 bajtova podataka. Osim toga, u EAV svi vrijednosti svojstava pohranjuju se u obliku teksta, dok JSONB koristi numeri\u010dke i logi\u010dke vrijednosti kada je to mogu\u0107e, \u0161to rezultira manjim volumenom.<\/p>\n<h3>Zaklju\u010dci<\/h3>\n<p>\nOp\u0107enito, mislim da o\u010duvanje svojstava entiteta u JSONB formatu mo\u017ee zna\u010dajno pojednostaviti dizajn i odr\u017eavanje va\u0161e baze podataka. Ako izvr\u0161avate mnogo upita, sve \u0161to je pohranjeno u jednoj tablici s entitetom zapravo \u0107e raditi u\u010dinkovitije. A \u010dinjenica da to olak\u0161ava interakciju izme\u0111u podataka ve\u0107 je plus, ali tako\u0111er rezultantna Baza podataka je 3 puta manja po volumenu.<\/p>\n<p>Tako\u0111er, na temelju provedenih testova, mo\u017ee se zaklju\u010diti da su gubici u performansama vrlo neznatni. U nekim slu\u010dajevima, JSONB \u010dak radi br\u017ee od EAV, \u0161to ga \u010dini jo\u0161 boljim. Me\u0111utim, ovaj referentni test, naravno, ne pokriva sve aspekte (npr. entiteti s vrlo velikim brojem svojstava, zna\u010dajnim pove\u0107anjem broja svojstava postoje\u0107ih podataka,\u2026), stoga, ako imate bilo kakve prijedloge o tome kako ih pobolj\u0161ati, slobodno ostavite u komentarima!<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\/hr\/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=\"hr_HR\" \/>\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\/hr\/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\udd47Zamjena EAV s JSONB u PostgreSQL | ProHoster","description":"TL; DR: JSONB mo\u017ee zna\u010dajno pojednostaviti razvoj sheme baze podataka bez ugro\u017eavanja performansi u upitima. Uvod Donijet \u0107emo klasi\u010dan primjer, vjerojatno jedan od najstarijih.","canonical_url":"https:\/\/prohoster.info\/hr\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"hr_HR","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\/hr\/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\/hr\/wp-json\/wp\/v2\/posts\/52584","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/comments?post=52584"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts\/52584\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/media?parent=52584"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/categories?post=52584"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/tags?post=52584"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}