{"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\/sk\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","title":{"rendered":"Nahradenie EAV za JSONB v PostgreSQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<blockquote><p>TL; DR: JSONB m\u00f4\u017ee v\u00fdznamne zjednodu\u0161i\u0165 n\u00e1vrh sch\u00e9my datab\u00e1zy bez negat\u00edvneho dopadu na v\u00fdkon pri dotazoch.<\/p><\/blockquote>\n<p><\/p>\n<h3>\u00davod<\/h3>\n<p>\nUve\u010fme klasick\u00fd pr\u00edklad, pravdepodobne jedn\u00e9ho z najstar\u0161\u00edch sp\u00f4sobov pou\u017eitia vo svete rela\u010dn\u00fdch datab\u00e1z (datab\u00e1za): m\u00e1me entitu a potrebujeme ulo\u017ei\u0165 ur\u010dit\u00e9 vlastnosti (atrib\u00faty) tejto entity. Ale nie v\u0161etky in\u0161tancie m\u00f4\u017eu ma\u0165 rovnak\u00fa mno\u017einu vlastnost\u00ed, navy\u0161e v bud\u00facnosti je mo\u017en\u00e9 prida\u0165 \u010fal\u0161ie vlastnosti.<\/p>\n<p>Najjednoduch\u0161\u00ed sp\u00f4sob, ako t\u00fato ot\u00e1zku vyrie\u0161i\u0165, je vytvorenie st\u013apca v tabu\u013eke datab\u00e1zy pre ka\u017ed\u00fa hodnotu vlastnosti a jednoducho vyplni\u0165 tie, ktor\u00e9 s\u00fa potrebn\u00e9 pre konkr\u00e9tnu in\u0161tanciu entity. V\u00fdborne! Probl\u00e9m je vyrie\u0161en\u00fd... do chv\u00edle, k\u00fdm va\u0161a tabu\u013eka neobsahuje mili\u00f3ny z\u00e1znamov a nezjav\u00ed sa potreba prida\u0165 nov\u00fd z\u00e1znam.<\/p>\n<p>Zv\u00e1\u017eme vzor EAV (<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Entity%E2%80%93attribute%E2%80%93value_model\">Entity-Attribute-Value<\/a><\/noindex>), ktor\u00fd sa \u010dasto vyskytuje. Jedna tabu\u013eka obsahuje entity (z\u00e1znamy), druh\u00e1 tabu\u013eka obsahuje men\u00e1 vlastnost\u00ed (atrib\u00fatov), a tre\u0165a tabu\u013eka prepojuje entity s ich atrib\u00fatmi a obsahuje hodnoty t\u00fdchto atrib\u00fatov pre aktu\u00e1lnu entitu. To v\u00e1m umo\u017e\u0148uje ma\u0165 r\u00f4zne mno\u017einy vlastnost\u00ed pre r\u00f4zne objekty a tie\u017e prid\u00e1va\u0165 vlastnosti \u201eza behu\u201c, bez zmeny \u0161trukt\u00fary datab\u00e1zy.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nNapriek tomu by som nenap\u00edsal t\u00fato pozn\u00e1mku, keby nebolo nev\u00fdhod pr\u00edstupu s vyu\u017eit\u00edm EVA. Napr\u00edklad, na z\u00edskanie jednej alebo viacer\u00fdch ent\u00edt, ktor\u00e9 maj\u00fa po 1 atrib\u00fat, s\u00fa potrebn\u00e9 2 joiny (zjednotenia) v dotaze: prv\u00fd \u2013 zjednotenie s tabu\u013ekou atrib\u00fatov, druh\u00fd \u2013 zjednotenie s tabu\u013ekou hodn\u00f4t. Ak entita m\u00e1 2 atrib\u00faty, tak potrebujete u\u017e 4 joiny! Okrem toho, v\u0161etky atrib\u00faty s\u00fa zvy\u010dajne ulo\u017een\u00e9 vo forme re\u0165azcov, \u010do vedie k prevodu typov, ako pre v\u00fdsledok, tak aj pre podmienku WHERE. Ak p\u00ed\u0161ete ve\u013ea dotazov, je to dos\u0165 plytvanie z h\u013eadiska vyu\u017eitia zdrojov.<\/p>\n<p>Napriek t\u00fdmto evidentn\u00fdm nev\u00fdhod\u00e1m sa EAV u\u017e dlho pou\u017e\u00edva na rie\u0161enie tak\u00fdchto probl\u00e9mov. Boli to nevyhnutn\u00e9 nev\u00fdhody a lep\u0161ia alternat\u00edva jednoducho neexistovala. <br \/>\nAle potom sa v PostgreSQL objavila nov\u00e1 \u201etechnol\u00f3gia\u201c\u2026<\/p>\n<p>Od verzie PostgreSQL 9.4 bol pridan\u00fd typ d\u00e1t JSONB na uchov\u00e1vanie bin\u00e1rnych d\u00e1t JSON. Hoci ulo\u017eenie JSON v tomto form\u00e1te obvykle zaber\u00e1 o nie\u010do viac miesta a \u010dasu ako jednoduch\u00fd textov\u00fd JSON, vykon\u00e1vanie oper\u00e1ci\u00ed s n\u00edm je ove\u013ea r\u00fdchlej\u0161ie. JSONB tie\u017e podporuje indexovanie, \u010do e\u0161te viac ur\u00fdch\u013euje dotazy.<\/p>\n<p>Typ d\u00e1t JSONB n\u00e1m umo\u017e\u0148uje nahradi\u0165 objemn\u00fd vzor EAV pridan\u00edm len jedn\u00e9ho st\u013apca JSONB do na\u0161ej tabu\u013eky ent\u00edt, \u010do v\u00fdrazne zjednodu\u0161\u00ed n\u00e1vrh datab\u00e1zy. Mnoh\u00ed v\u0161ak tvrdia, \u017ee to m\u00f4\u017ee vies\u0165 k zn\u00ed\u017eeniu v\u00fdkonu\u2026 Z tohto d\u00f4vodu vznikol tento \u010dl\u00e1nok.<\/p>\n<h3>Nastavenie testovacej datab\u00e1zy<\/h3>\n<p>\nPre toto porovnanie som vytvoril datab\u00e1zu na novej in\u0161tal\u00e1cii PostgreSQL 9.5 na zostave za 80 dol\u00e1rov. <noindex><a rel=\"nofollow\" href=\"https:\/\/www.digitalocean.com\/\">DigitalOcean<\/a><\/noindex> Ubuntu 14.04. Po nastaven\u00ed niektor\u00fdch parametrov v postgresql.conf som spustil <noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/coussej\/80c385332ce37df6687f\">web<\/a><\/noindex> skript pomocou psql. Pre predstavenie d\u00e1t vo forme EAV boli vytvoren\u00e9 nasleduj\u00face tabu\u013eky:<\/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>\nNi\u017e\u0161ie je tabu\u013eka, kde bud\u00fa uchov\u00e1van\u00e9 tie ist\u00e9 d\u00e1ta, ale s atrib\u00fatmi v st\u013apci typu 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>\nVyzer\u00e1 to omnoho jednoduch\u0161ie, \u017ee? Potom bolo do tabuliek ent\u00edt (<i>entity<\/i> &amp; <i>entity_jsonb<\/i>) pridan\u00fdch 10 mili\u00f3nov z\u00e1znamov a rovnako boli naplnen\u00e9 rovnak\u00fdmi d\u00e1tami tabu\u013eky, kde sa pou\u017e\u00edva vzor EAV a pr\u00edstup so st\u013apcom JSONB \u2013 <i>entity_jsonb.properties<\/i>. T\u00fdmto sp\u00f4sobom sme z\u00edskali nieko\u013eko r\u00f4znych typov d\u00e1t medzi cel\u00fdm s\u00faborom vlastnost\u00ed. Pr\u00edklad d\u00e1t:<\/p>\n<pre><code class=\"json\">{\n  id:          1\n  name:        \"Entity1\"\n  description: \"Testovacia entita \u010d. 1\"\n  properties:  {\n    color:        \"\u010derven\u00e1\"\n    length:       120\n    width:        3.1882420\n    hassomething: true\n    country:      \"Belgicko\"\n  } \n}<\/code><\/pre>\n<p>\nTak\u017ee teraz m\u00e1me rovnak\u00e9 d\u00e1ta pre dva varianty. Po\u010fme za\u010da\u0165 porovn\u00e1va\u0165 implement\u00e1cie v praxi!<\/p>\n<h3>Zjednodu\u0161enie dizajnu<\/h3>\n<p>\nU\u017e bolo spomenut\u00e9, \u017ee dizajn DB bol v\u00fdrazne zjednodu\u0161en\u00fd: jedna tabu\u013eka, v\u010faka pou\u017e\u00edvaniu st\u013apca JSONB pre vlastnosti, namiesto troch tabuliek pre EAV. Ako sa to v\u0161ak odr\u00e1\u017ea v dotazoch? Aktualiz\u00e1cia jedn\u00e9ho atrib\u00fatu entity vyzer\u00e1 nasledovne:<\/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>\nAko vid\u00edme, posledn\u00fd dotaz nevyzer\u00e1 jednoduch\u0161ie. Aby sme aktualizovali hodnotu vlastnosti v objekte JSONB, mus\u00edme pou\u017ei\u0165 funkciu <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.5\/static\/functions-json.html\">jsonb_set()<\/a><\/noindex>, a mus\u00edme odovzda\u0165 na\u0161u nov\u00fa hodnotu ako objekt JSONB. Napriek tomu nemus\u00edme vedie\u0165 \u017eiadny identifik\u00e1tor vopred. Pri poh\u013eade na pr\u00edklad s EAV potrebujeme pozna\u0165 aj entity_id, aj entity_attribute_id, aby sme mohli vykona\u0165 aktualiz\u00e1ciu. Ak chcete aktualizova\u0165 vlastnos\u0165 v st\u013apci JSONB na z\u00e1klade mena objektu, \u2013 to v\u0161etko sa rob\u00ed jedn\u00fdm jednoduch\u00fdm riadkom.<\/p>\n<p>Teraz si vyberme t\u00fa entitu, ktor\u00fa sme pr\u00e1ve aktualizovali, na z\u00e1klade jej novej farby:<\/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>\nMysl\u00edm, \u017ee sa m\u00f4\u017eeme zhodn\u00fa\u0165 na tom, \u017ee druh\u00e9 je krat\u0161ie (bez join!), a preto aj \u010ditate\u013enej\u0161ie. Tu vyhr\u00e1va JSONB! Pou\u017e\u00edvame oper\u00e1tor JSON -&gt;&gt;, aby sme z\u00edskali farbu ako textov\u00fa hodnotu z objektu JSONB. Existuje aj druh\u00fd sp\u00f4sob, ako dosiahnu\u0165 ten ist\u00fd v\u00fdsledok v modeli JSONB pomocou oper\u00e1tora @&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 trochu zlo\u017eitej\u0161ie: kontrolujeme, \u010di objekt JSON v st\u013apci vlastnost\u00ed obsahuje objekt, ktor\u00fd sa nach\u00e1dza napravo od oper\u00e1tora @&gt;. Menej \u010ditate\u013en\u00e9, ale v\u00fdkonn\u011bj\u0161\u00ed (pozri \u010falej). <\/p>\n<p>Zjednodu\u0161me pou\u017e\u00edvanie JSONB e\u0161te viac, ke\u010f potrebujete vybra\u0165 viac vlastnost\u00ed naraz. Tu sa naozaj hod\u00ed pr\u00edstup JSONB: jednoducho vyber\u00e1me vlastnosti ako \u010fal\u0161ie st\u013apce v na\u0161ej sadzbe v\u00fdsledkov bez potreby joinov:<\/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 budete potrebova\u0165 2 joiny pre ka\u017ed\u00fa vlastnos\u0165, ktor\u00fa chcete dotazova\u0165. Pod\u013ea m\u00f4jho n\u00e1zoru uveden\u00e9 dotazy ukazuj\u00fa ve\u013ek\u00e9 zjednodu\u0161enie v dizajne datab\u00e1zy. Viac pr\u00edkladov, ako p\u00edsa\u0165 dotazy na JSONB, mo\u017eno n\u00e1js\u0165 tie\u017e v <noindex><a rel=\"nofollow\" href=\"http:\/\/schinckel.net\/2014\/05\/25\/querying-json-in-postgres\/\">tom<\/a><\/noindex> pr\u00edspevku.<br \/>\nTeraz je \u010das hovori\u0165 o v\u00fdkonnosti.<\/p>\n<h3>V\u00fdkon<\/h3>\n<p>\nAby sme porovnali v\u00fdkonnos\u0165, pou\u017eil som <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/sql-explain.html\">EXPLAIN ANALYZE<\/a><\/noindex> v dopytoch na v\u00fdpo\u010det \u010dasu vykonania. Ka\u017ed\u00fd dopyt bol vykonan\u00fd aspo\u0148 trikr\u00e1t, preto\u017ee pl\u00e1nova\u010d dopytov potrebuje viac \u010dasu na prv\u00fd pokus. Najprv som vykonal dopyty bez ak\u00fdchko\u013evek indexov. Je zrejm\u00e9, \u017ee to bolo v\u00fdhodou JSONB, ke\u010f\u017ee pripojenia potrebn\u00e9 pre EAV nemohli vyu\u017e\u00edva\u0165 indexy (polia cudz\u00edch k\u013e\u00fa\u010dov neboli indexovan\u00e9). Potom som vytvoril index na 2 st\u013apce cudz\u00edch k\u013e\u00fa\u010dov v tabu\u013eke hodn\u00f4t EAV, ako aj index <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/textsearch-indexes.html\">GIN<\/a><\/noindex> pre st\u013apec JSONB.<\/p>\n<p>Aktualiz\u00e1cie \u00fadajov uk\u00e1zali nasleduj\u00face v\u00fdsledky v \u010dase (v ms). V\u0161imnite si, \u017ee \u0161k\u00e1la je logaritmick\u00e1:<\/p>\n<p><img decoding=\"async\" alt=\"Nahradenie EAV za JSONB v PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/8a12ccd7a46d04868b1cc5fcaf01a581.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nVid\u00edme, \u017ee JSONB je ove\u013ea (&gt; 50000-kr\u00e1t) r\u00fdchlej\u0161\u00ed ako EAV, ak sa indexy nepou\u017e\u00edvaj\u00fa, z d\u00f4vodu uveden\u00e9ho vy\u0161\u0161ie. Ke\u010f indexujeme st\u013apce s prim\u00e1rnymi k\u013e\u00fa\u010dmi, rozdiel takmer zmizne, ale JSONB je st\u00e1le 1,3-kr\u00e1t r\u00fdchlej\u0161\u00ed ako EAV. Majte na pam\u00e4ti, \u017ee index v st\u013apci JSONB tu nem\u00e1 \u017eiadny vplyv, preto\u017ee nepou\u017e\u00edvame st\u013apec vlastnost\u00ed v hodnotiacich krit\u00e9ri\u00e1ch. <\/p>\n<p>Pre v\u00fdber \u00fadajov na z\u00e1klade hodnoty vlastnosti dost\u00e1vame nasleduj\u00face v\u00fdsledky (be\u017en\u00e1 \u0161k\u00e1la):<\/p>\n<p><img decoding=\"async\" alt=\"Nahradenie EAV za JSONB v PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/e9a1fd797ef60132e661da686f6214a3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nM\u00f4\u017eeme si v\u0161imn\u00fa\u0165, \u017ee JSONB znova funguje r\u00fdchlej\u0161ie ako EAV bez indexov, ale ke\u010f EAV m\u00e1 indexy, st\u00e1le funguje r\u00fdchlej\u0161ie ako JSONB. Potom som si v\u0161imol, \u017ee \u010das pre dopyty JSONB bol rovnak\u00fd, \u010do ma priviedlo k zisteniu, \u017ee GIN-index nefunguje. Zjavne, ke\u010f pou\u017e\u00edvate index GIN pre st\u013apec so zaplnen\u00fdmi vlastnos\u0165ami, funguje to iba pri pou\u017eit\u00ed oper\u00e1tora pr\u00edtomnosti @&gt;. Pou\u017eil som to v novom teste, \u010do malo obrovsk\u00fd dopad na \u010das: iba 0,153 ms! To je 15000-kr\u00e1t r\u00fdchlej\u0161ie ako EAV a 25000-kr\u00e1t r\u00fdchlej\u0161ie ako oper\u00e1tor -&gt;&gt; <\/p>\n<p>Mysl\u00edm, \u017ee to bolo dos\u0165 r\u00fdchle!<\/p>\n<h3>Ve\u013ekos\u0165 tabuliek DB<\/h3>\n<p>\nPorovnajme ve\u013ekosti tabuliek pri oboch pr\u00edstupoch. V psql m\u00f4\u017eeme zobrazi\u0165 ve\u013ekos\u0165 v\u0161etk\u00fdch tabuliek a indexov pomocou pr\u00edkazu <b>dti+<\/b><\/p>\n<p><img decoding=\"async\" alt=\"Nahradenie EAV za JSONB v PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/c6c1fe7901fe9ae2bd446cf4ae99b923.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPre pr\u00edstup EAV s\u00fa ve\u013ekosti tabuliek pribli\u017ene 3068 MB a indexy a\u017e 3427 MB, \u010do v s\u00fa\u010dte d\u00e1va 6,43 GB. Pri pou\u017eit\u00ed pr\u00edstupu s JSONB sa pou\u017e\u00edva 1817 MB pre tabu\u013eku a 318 MB pre indexy, \u010do predstavuje 2,08 GB. To je trikr\u00e1t menej! Tento fakt ma trochu prekvapil, preto\u017ee uchov\u00e1vame n\u00e1zvy vlastnost\u00ed v ka\u017edom objekte JSONB. <\/p>\n<p>Ale predsa \u010d\u00edsla hovoria sama za seba: v EAV uchov\u00e1vame 2 cel\u00e9 \u010d\u00edsla ako extern\u00e9 k\u013e\u00fa\u010de na hodnotu atrib\u00fatu, \u010do vedie k dodato\u010dn\u00fdm 8 bajtom d\u00e1t. Okrem toho, v EAV s\u00fa v\u0161etky hodnoty vlastnost\u00ed ulo\u017een\u00e9 ako text, zatia\u013e \u010do JSONB pou\u017e\u00edva \u010d\u00edseln\u00e9 a logick\u00e9 hodnoty tam, kde je to mo\u017en\u00e9, \u010d\u00edm sa dosiahne men\u0161\u00ed objem.<\/p>\n<h3>Zhrnutie<\/h3>\n<p>\nCelkovo si mysl\u00edm, \u017ee uchov\u00e1vanie vlastnost\u00ed ent\u00edt vo form\u00e1te JSONB m\u00f4\u017ee v\u00fdrazne zjednodu\u0161i\u0165 n\u00e1vrh a \u00fadr\u017ebu va\u0161ej datab\u00e1zy. Ak vykon\u00e1vate ve\u013ea dotazov, v\u0161etko, \u010do je ulo\u017een\u00e9 v jednej tabu\u013eke s entitou, bude skuto\u010dne fungova\u0165 efekt\u00edvnej\u0161ie. A to, \u017ee to zjednodu\u0161uje interakciu medzi \u00fadajmi, je u\u017e plusom, ale aj v\u00fdsledn\u00e1 datab\u00e1za je trikr\u00e1t men\u0161ia z objemu.<\/p>\n<p>Tie\u017e, pod\u013ea vykonan\u00e9ho testu, je mo\u017en\u00e9 urobi\u0165 z\u00e1ver, \u017ee straty v\u00fdkonu s\u00fa ve\u013emi nepatrn\u00e9. V niektor\u00fdch pr\u00edpadoch JSONB dokonca funguje r\u00fdchlej\u0161ie ako EAV, \u010do ho rob\u00ed e\u0161te lep\u0161\u00edm. Av\u0161ak tento referen\u010dn\u00fd test samozrejme nezah\u0155\u0148a v\u0161etky aspekty (napr\u00edklad entity s ve\u013emi ve\u013ek\u00fdm po\u010dtom vlastnost\u00ed, v\u00fdznamn\u00fdm zv\u00fd\u0161en\u00edm po\u010dtu vlastnost\u00ed existuj\u00facich \u00fadajov...), preto, ak m\u00e1te nejak\u00e9 n\u00e1vrhy na ich zlep\u0161enie, nev\u00e1hajte zanecha\u0165 koment\u00e1re!<br \/>\n<br \/>Zdroj: <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.5 - 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\/sk\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.5\" \/>\n\t\t<meta property=\"og:locale\" content=\"sk_SK\" \/>\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\/sk\/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\udd47Nahradenie EAV s JSONB v PostgreSQL | ProHoster","description":"TL; DR: JSONB m\u00f4\u017ee v\u00fdrazne zjednodu\u0161i\u0165 v\u00fdvoj sch\u00e9my DB bez po\u0161kodenia v\u00fdkonu pri dotazoch. \u00davod Predstav\u00edme klasick\u00fd pr\u00edklad, pravdepodobne jedn\u00e9ho z najstar\u0161\u00edch.","canonical_url":"https:\/\/prohoster.info\/sk\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sk_SK","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\/sk\/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\/sk\/wp-json\/wp\/v2\/posts\/52584","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/comments?post=52584"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/posts\/52584\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/media?parent=52584"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/categories?post=52584"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/tags?post=52584"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}