{"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\/ro\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","title":{"rendered":"\u00cenlocuirea EAV cu JSONB \u00een PostgreSQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<blockquote><p>TL; DR: JSONB poate simplifica semnificativ dezvoltarea schemei de baz\u0103 de date f\u0103r\u0103 a compromite performan\u021ba interog\u0103rilor.<\/p><\/blockquote>\n<p><\/p>\n<h3>Introducere<\/h3>\n<p>\nS\u0103 lu\u0103m un exemplu clasic, probabil unul dintre cele mai vechi moduri de utilizare \u00een lumea bazelor de date rela\u021bionale: avem o entitate \u0219i trebuie s\u0103 salv\u0103m anumite propriet\u0103\u021bi (atribute) ale acestei entit\u0103\u021bi. Dar nu toate instan\u021bele pot avea acela\u0219i set de propriet\u0103\u021bi, iar \u00een plus, posibilitatea de a ad\u0103uga \u00eenc\u0103 propriet\u0103\u021bi \u00een viitor.<\/p>\n<p>Cea mai simpl\u0103 solu\u021bie pentru aceast\u0103 problem\u0103 este crearea unei coloane \u00een tabela de baz\u0103 de date pentru fiecare valoare de proprietate \u0219i pur \u0219i simplu completarea celor necesare pentru o anumit\u0103 instan\u021b\u0103 a entit\u0103\u021bii. Excelent! Problema a fost rezolvat\u0103\u2026 p\u00e2n\u0103 \u00een momentul \u00een care tabela ta nu con\u021bine milioane de \u00eenregistr\u0103ri \u0219i ai nevoie s\u0103 adaugi o nou\u0103 \u00eenregistrare.<\/p>\n<p>S\u0103 lu\u0103m \u00een considerare modelul EAV (<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Entity%E2%80%93attribute%E2%80%93value_model\">Entity-Attribute-Value<\/a><\/noindex>), care este destul de frecvent \u00eent\u00e2lnit. O tabel\u0103 con\u021bine entit\u0103\u021bi (\u00eenregistr\u0103ri), o alt\u0103 tabel\u0103 con\u021bine numele propriet\u0103\u021bilor (atributelor), iar a treia tabel\u0103 leag\u0103 entit\u0103\u021bile de atributele lor \u0219i con\u021bine valorile acestor atribute pentru entitatea curent\u0103. Aceasta \u00ee\u021bi ofer\u0103 posibilitatea de a avea seturi diferite de propriet\u0103\u021bi pentru diferite obiecte, precum \u0219i de a ad\u0103uga propriet\u0103\u021bi \u201edin mers\u201d, f\u0103r\u0103 a modifica structura bazei de date.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nTotu\u0219i, nu a\u0219 fi scris aceast\u0103 not\u0103 dac\u0103 nu ar fi existat dezavantaje \u00een abordarea cu utilizarea EVA. De exemplu, pentru ob\u021binerea uneia sau mai multor entit\u0103\u021bi care au c\u00e2te 1 atribut, sunt necesare 2 join-uri \u00een interogare: primul \u2013 unirea cu tabelul atributelor, al doilea \u2013 unirea cu tabelul valorilor. Dac\u0103 entitatea are 2 atribute, atunci sunt necesare deja 4 join-uri! \u00cen plus, toate atributele sunt de obicei stocate sub form\u0103 de siruri, ceea ce duce la conversii de tip, at\u00e2t pentru rezultat, c\u00e2t \u0219i pentru condi\u021bia WHERE. Dac\u0103 scrie\u021bi multe interog\u0103ri, atunci aceasta este destul de risipitoare din punctul de vedere al utiliz\u0103rii resurselor.<\/p>\n<p>\u00cen ciuda acestor dezavantaje evidente, EAV este folosit de mult timp pentru a solu\u021biona acest tip de probleme. Acestea au fost dezavantaje inevitabile, iar o alternativ\u0103 mai bun\u0103 pur \u0219i simplu nu a existat. <br \/>\nDar apoi \u00een PostgreSQL a ap\u0103rut o nou\u0103 \u201etehnologie\u201d...<\/p>\n<p>\u00cencep\u00e2nd cu PostgreSQL 9.4, a fost ad\u0103ugat tipul de date JSONB pentru stocarea datelor JSON binare. De\u0219i stocarea JSON \u00een acest format ocup\u0103 de obicei pu\u021bin mai mult spa\u021biu \u0219i timp dec\u00e2t JSON-ul simplu, executarea opera\u021biunilor cu el se face mult mai rapid. De asemenea, JSONB suport\u0103 indexarea, ceea ce face ca interog\u0103rile s\u0103 fie \u0219i mai rapide.<\/p>\n<p>Tipul de date JSONB ne permite s\u0103 \u00eenlocuim modelul EAV voluminos prin ad\u0103ugarea unei singure coloane JSONB \u00een tabela noastr\u0103 de entit\u0103\u021bi, ceea ce simplific\u0103 semnificativ proiectarea bazei de date. Dar mul\u021bi sus\u021bin c\u0103 acest lucru ar trebui s\u0103 vin\u0103 cu o sc\u0103dere a performan\u021bei\u2026 De aceea a ap\u0103rut acest articol.<\/p>\n<h3>Configurarea bazei de date de testare<\/h3>\n<p>\nPentru aceast\u0103 compara\u021bie, am creat o baz\u0103 de date pe o instalare nou\u0103 PostgreSQL 9.5 pe o configura\u021bie de 80 de dolari <noindex><a rel=\"nofollow\" href=\"https:\/\/www.digitalocean.com\/\">DigitalOcean<\/a><\/noindex> Ubuntu 14.04. Dup\u0103 configurarea unor set\u0103ri \u00een postgresql.conf, am rulat <noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/coussej\/80c385332ce37df6687f\">aceasta<\/a><\/noindex> scriptul folosind psql. Pentru a reprezenta datele \u00eentr-un format EAV, au fost create urm\u0103toarele 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>\nMai jos este tabelul unde vor fi stocate acelea\u0219i date, dar cu atribute \u00een coloana de tip 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>\nArat\u0103 mult mai simplu, nu-i a\u0219a? Apoi au fost ad\u0103ugate \u00een tabelele entit\u0103\u021bilor (<i>entity<\/i> &amp; <i>entity_jsonb<\/i>) 10 milioane de \u00eenregistr\u0103ri \u0219i, \u00een consecin\u021b\u0103, au fost completate cu date identice tabelele \u00een care se folose\u0219te modelul EAV \u0219i abordarea cu coloana JSONB \u2013 <i>entity_jsonb.properties<\/i>. Astfel, am ob\u021binut mai multe tipuri diferite de date \u00een \u00eentregul set de propriet\u0103\u021bi. Exemplu de date:<\/p>\n<pre><code class=\"json\">{\n  id:          1\n  name:        \"Entity1\"\n  description: \"Entitate de test nr. 1\"\n  properties:  {\n    color:        \"ro\u0219u\"\n    length:       120\n    width:        3.1882420\n    hassomething: true\n    country:      \"Belgia\"\n  } \n}<\/code><\/pre>\n<p>\nDeci, acum avem date identice pentru cele dou\u0103 variante. S\u0103 \u00eencepem s\u0103 compar\u0103m implement\u0103rile \u00een practic\u0103!<\/p>\n<h3>Simplificarea designului<\/h3>\n<p>\nA fost men\u021bionat anterior c\u0103 designul bazei de date a fost semnificativ simplificat: o singur\u0103 tabel\u0103, datorit\u0103 utiliz\u0103rii coloanei JSONB pentru propriet\u0103\u021bi, \u00een loc de utilizarea a trei tabele pentru EAV. Dar cum se reflect\u0103 acest lucru \u00een interog\u0103ri? Actualizarea unei propriet\u0103\u021bi a entit\u0103\u021bii arat\u0103 astfel:<\/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>\nDup\u0103 cum vedem, ultima interogare nu arat\u0103 mai simpl\u0103. Pentru a actualiza valoarea unei propriet\u0103\u021bi \u00een obiectul JSONB, trebuie s\u0103 folosim func\u021bia <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.5\/static\/functions-json.html\">jsonb_set()<\/a><\/noindex>, \u0219i trebuie s\u0103 transmitem noua noastr\u0103 valoare ca obiect JSONB. Totu\u0219i, nu trebuie s\u0103 \u0219tim niciun identificator dinainte. Privind exemplul cu EAV, trebuie s\u0103 \u0219tim at\u00e2t entity_id, c\u00e2t \u0219i entity_attribute_id pentru a efectua actualizarea. Dac\u0103 dore\u0219ti s\u0103 actualizezi o proprietate \u00een coloana JSONB pe baza numelui obiectului, acest lucru se face totul cu un singur r\u00e2nd simplu.<\/p>\n<p>Acum s\u0103 select\u0103m entitatea pe care am actualizat-o, pe baza noului s\u0103u color:<\/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>\nCred c\u0103 putem conveni c\u0103 a doua este mai scurt\u0103 (f\u0103r\u0103 join!), \u0219i astfel mai u\u0219or de citit. Aici c\u00e2\u0219tig\u0103 JSONB! Folosim operatorul JSON -&gt;&gt;, pentru a ob\u021bine culoarea ca valoare text din obiectul JSONB. Exist\u0103, de asemenea, o a doua metod\u0103 de a ob\u021bine acela\u0219i rezultat \u00een modelul JSONB folosind operatorul @&gt;:<\/p>\n<pre><code class=\"pgsql\">-- JSONB \nSELECT name \nFROM entity_jsonb \nWHERE properties @&gt; '{\"color\": \"blue\"}';\n<\/code><\/pre>\n<p>\nEste pu\u021bin mai complicat: verific\u0103m dac\u0103 obiectul JSON din coloana propriet\u0103\u021bi con\u021bine obiectul care se afl\u0103 \u00een dreapta operatorului @&gt;. Mai pu\u021bin citibil, dar mai performant (vezi mai departe). <\/p>\n<p>S\u0103 simplific\u0103m utilizarea JSONB \u0219i mai mult, atunci c\u00e2nd trebuie s\u0103 select\u0103m mai multe propriet\u0103\u021bi simultan. Aici se potrive\u0219te cu adev\u0103rat abordarea JSONB: pur \u0219i simplu select\u0103m propriet\u0103\u021bile ca coloane suplimentare \u00een setul nostru de rezultate f\u0103r\u0103 necesitatea de a face unire:<\/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>\nCu EAV, vei avea nevoie de 2 uniuni pentru fiecare proprietate pe care vrei s\u0103 o interoghezi. Din punctul meu de vedere, interog\u0103rile de mai sus arat\u0103 o mare simplificare \u00een designul bazei de date. Po\u021bi viziona mai multe exemple despre cum s\u0103 scrii interog\u0103ri pentru JSONB, posibile \u0219i \u00een <noindex><a rel=\"nofollow\" href=\"http:\/\/schinckel.net\/2014\/05\/25\/querying-json-in-postgres\/\">aceasta<\/a><\/noindex> post.<br \/>\nAcum a venit timpul s\u0103 vorbim despre performan\u021b\u0103.<\/p>\n<h3>Performan\u021b\u0103<\/h3>\n<p>\nPentru a compara performan\u021ba, am folosit <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/sql-explain.html\">EXPLAIN ANALYZE<\/a><\/noindex> \u00een interog\u0103ri, pentru calcularea timpului de execu\u021bie. Fiecare interogare a fost efectuat\u0103 de cel pu\u021bin trei ori, deoarece prima dat\u0103 planificatorului de interog\u0103ri \u00eei trebuie mai mult timp. La \u00eenceput, am efectuat interog\u0103rile f\u0103r\u0103 indec\u0219i. Evident, acest lucru a fost un avantaj pentru JSONB, deoarece join-urile necesare pentru EAV nu puteau folosi indec\u0219i (c\u00e2mpurile cheie str\u0103ine nu erau indexate). Dup\u0103 aceea, am creat un indice pentru cele dou\u0103 coloane ale cheilor externe din tabela valorilor EAV, precum \u0219i un indice <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/textsearch-indexes.html\">GIN<\/a><\/noindex> pentru coloana JSONB.<\/p>\n<p>Actualiz\u0103rile de date au ar\u0103tat urm\u0103toarele rezultate \u00een timp (\u00een ms). Re\u021bine\u021bi c\u0103 scala este logaritmic\u0103:<\/p>\n<p><img decoding=\"async\" alt=\"\u00cenlocuirea EAV cu JSONB \u00een PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/8a12ccd7a46d04868b1cc5fcaf01a581.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSe observ\u0103 c\u0103 JSONB este cu mult (&gt; 50000-x) mai rapid dec\u00e2t EAV, dac\u0103 nu folosim indec\u0219i, din cauza men\u021bionat\u0103 mai sus. C\u00e2nd index\u0103m coloanele cu chei primare, diferen\u021ba aproape dispare, dar JSONB r\u0103m\u00e2ne totu\u0219i de 1,3 ori mai rapid dec\u00e2t EAV. Re\u021bine\u021bi c\u0103 indicele din coloana JSONB nu are nicio influen\u021b\u0103 aici, deoarece nu folosim coloana propriet\u0103\u021bilor \u00een criteriile de evaluare. <\/p>\n<p>Pentru selectarea datelor pe baza valorii propriet\u0103\u021bii, ob\u021binem urm\u0103toarele rezultate (scala normal\u0103):<\/p>\n<p><img decoding=\"async\" alt=\"\u00cenlocuirea EAV cu JSONB \u00een PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/e9a1fd797ef60132e661da686f6214a3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSe poate observa c\u0103 JSONB lucreaz\u0103 din nou mai repede dec\u00e2t EAV f\u0103r\u0103 indec\u0219i, dar c\u00e2nd EAV are indec\u0219i \u0219i totu\u0219i func\u021bioneaz\u0103 mai rapid dec\u00e2t JSONB. Dar apoi am observat c\u0103 timpul pentru interog\u0103rile JSONB a fost acela\u0219i, ceea ce m-a determinat s\u0103 cred c\u0103 indicele GIN nu func\u021bioneaz\u0103. Se pare c\u0103, atunci c\u00e2nd folose\u0219ti un indice GIN pentru o coloan\u0103 cu propriet\u0103\u021bi completate, acesta ac\u021bioneaz\u0103 doar atunci c\u00e2nd se folose\u0219te operatorul de includere @&gt;. Am folosit asta \u00eentr-un nou test, ceea ce a avut un impact uria\u0219 asupra timpului: doar 0,153 ms! Este cu 15000 de ori mai rapid dec\u00e2t EAV \u0219i cu 25000 de ori mai rapid dec\u00e2t operatorul -&gt;&gt;. <\/p>\n<p>Cred c\u0103 a fost destul de rapid!<\/p>\n<h3>Dimensiunea tabelelor DB<\/h3>\n<p>\nS\u0103 compar\u0103m dimensiunile tabelelor \u00een ambele abord\u0103ri. \u00cen psql putem ar\u0103ta dimensiunea tuturor tabelelor \u0219i indec\u0219ilor folosind comanda <b>dti+<\/b><\/p>\n<p><img decoding=\"async\" alt=\"\u00cenlocuirea EAV cu JSONB \u00een PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/c6c1fe7901fe9ae2bd446cf4ae99b923.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPentru abordarea EAV, dimensiunile tabelelor sunt de aproximativ 3068 MB, iar indec\u0219ii sunt p\u00e2n\u0103 la 3427 MB, ceea ce totalizeaz\u0103 6,43 GB. Folosind abordarea cu JSONB, se folosesc 1817 MB pentru tabel \u0219i 318 MB pentru indec\u0219i, ceea ce reprezint\u0103 2,08 GB. Este de trei ori mai pu\u021bin! Acest fapt m-a surprins pu\u021bin, deoarece stoc\u0103m numele propriet\u0103\u021bilor \u00een fiecare obiect JSONB. <\/p>\n<p>Dar totu\u0219i, cifrele vorbesc de la sine: \u00een EAV stoc\u0103m 2 chei externe \u00eentregi pentru valoarea atributului, ob\u021bin\u00e2nd astfel 8 byte de date suplimentare. \u00cen plus, \u00een EAV toate valorile propriet\u0103\u021bilor sunt stocate sub form\u0103 de text, \u00een timp ce JSONB va folosi valori numerice \u0219i logice acolo unde este posibil, rezult\u00e2nd un volum mai mic.<\/p>\n<h3>Concluzii<\/h3>\n<p>\n\u00cen general, cred c\u0103 p\u0103strarea propriet\u0103\u021bilor entit\u0103\u021bilor \u00een format JSONB poate simplifica semnificativ proiectarea \u0219i \u00eentre\u021binerea bazei dumneavoastr\u0103 de date. Dac\u0103 efectua\u021bi multe interog\u0103ri, tot ce este stocat \u00eentr-o singur\u0103 tabel\u0103 cu entitatea va func\u021biona cu adev\u0103rat mai eficient. \u0218i faptul c\u0103 simplific\u0103 interac\u021biunea \u00eentre date deja reprezint\u0103 un avantaj, dar \u0219i baza de date rezultant\u0103 este de 3 ori mai mic\u0103 ca volum.<\/p>\n<p>De asemenea, din testele efectuate, se poate concluziona c\u0103 pierderile de performan\u021b\u0103 sunt foarte neglijabile. \u00cen unele cazuri, JSONB func\u021bioneaz\u0103 chiar mai repede dec\u00e2t EAV, ceea ce \u00eel face \u0219i mai bun. Cu toate acestea, acest test de referin\u021b\u0103 nu acoper\u0103 toate aspectele (de exemplu, entit\u0103\u021bi cu un num\u0103r foarte mare de propriet\u0103\u021bi, o cre\u0219tere semnificativ\u0103 a num\u0103rului de propriet\u0103\u021bi ale datelor existente,\u2026), a\u0219a c\u0103, dac\u0103 ave\u021bi sugestii despre cum s\u0103 le \u00eembun\u0103t\u0103\u021bi\u021bi, nu ezita\u021bi s\u0103 le l\u0103sa\u021bi \u00een comentarii!<br \/>\n<br \/>Sursa: <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.2 - 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\/ro\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"ro_RO\" \/>\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\/ro\/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\udd47\u00cenlocuirea EAV cu JSONB \u00een PostgreSQL | ProHoster","description":"TL; DR: JSONB poate simplifica semnificativ dezvoltarea schemei bazei de date f\u0103r\u0103 a afecta performan\u021ba interog\u0103rilor. Introducere. S\u0103 d\u0103m un exemplu clasic, probabil, unul dintre cele mai vechi.","canonical_url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"ro_RO","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\/ro\/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\/ro\/wp-json\/wp\/v2\/posts\/52584","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/comments?post=52584"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/52584\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media?parent=52584"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/categories?post=52584"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/tags?post=52584"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}