{"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\/hu\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","title":{"rendered":"EAV helyettes\u00edt\u00e9se JSONB-ra PostgreSQL-ben","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<blockquote><p>R\u00f6viden: a JSONB jelent\u0151sen megk\u00f6nny\u00edtheti az adatb\u00e1zis s\u00e9ma fejleszt\u00e9s\u00e9t an\u00e9lk\u00fcl, hogy a lek\u00e9rdez\u00e9sek teljes\u00edtm\u00e9nye cs\u00f6kkenne.<\/p><\/blockquote>\n<p><\/p>\n<h3>Bevezet\u00e9s<\/h3>\n<p>\nVegy\u00fcnk egy klasszikus p\u00e9ld\u00e1t, val\u00f3sz\u00edn\u0171leg az egyik legr\u00e9gebbi felhaszn\u00e1l\u00e1si m\u00f3d\u00e9rt a rel\u00e1ci\u00f3s adatb\u00e1zisok vil\u00e1g\u00e1ban: van egy entit\u00e1sunk, \u00e9s meg kell \u0151rizn\u00fcnk ennek az entit\u00e1snak bizonyos jellemz\u0151it (attrib\u00fatumait). De nem minden p\u00e9ld\u00e1ny rendelkezik ugyanazzal a jellemz\u0151k\u00e9szlettel, r\u00e1ad\u00e1sul a j\u00f6v\u0151ben \u00faj jellemz\u0151k hozz\u00e1ad\u00e1sa is lehets\u00e9ges.<\/p>\n<p>A probl\u00e9ma leg egyszer\u0171bb megold\u00e1sa egy oszlop l\u00e9trehoz\u00e1sa az adatb\u00e1zis t\u00e1bl\u00e1j\u00e1ban minden egyes jellemz\u0151\u00e9rt, \u00e9s egyszer\u0171en a sz\u00fcks\u00e9ges jellemz\u0151ket kit\u00f6lteni az adott entit\u00e1s p\u00e9ld\u00e1ny\u00e1hoz. Szuper! A probl\u00e9ma megoldva\u2026 eg\u00e9szen addig, am\u00edg a t\u00e1bl\u00e1zatban nem milli\u00e1rdnyi bejegyz\u00e9s tal\u00e1lhat\u00f3, \u00e9s nem mer\u00fcl fel az \u00faj bejegyz\u00e9s hozz\u00e1ad\u00e1sa.<\/p>\n<p>N\u00e9zz\u00fck meg az EAV mint\u00e1t (<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Entity%E2%80%93attribute%E2%80%93value_model\">Entity-Attribute-Value<\/a><\/noindex>), amely meglehet\u0151sen gyakori. Az egyik t\u00e1bla az entit\u00e1sokat (bejegyz\u00e9seket) tartalmazza, a m\u00e1sik t\u00e1bla a jellemz\u0151k (attrib\u00fatumok) neveit, a harmadik t\u00e1bla pedig \u00f6sszekapcsolja az entit\u00e1sokat a jellemz\u0151ikkel, \u00e9s t\u00e1rolja e jellemz\u0151k \u00e9rt\u00e9keit az aktu\u00e1lis entit\u00e1s sz\u00e1m\u00e1ra. Ez lehet\u0151v\u00e9 teszi, hogy k\u00fcl\u00f6nb\u00f6z\u0151 jellemz\u0151k k\u00e9szletei legyenek k\u00fcl\u00f6nb\u00f6z\u0151 objektumok sz\u00e1m\u00e1ra, \u00e9s \u00faj jellemz\u0151ket adhassunk hozz\u00e1 \u201eszalagszer\u0171en\u201d, an\u00e9lk\u00fcl, hogy megv\u00e1ltoztatn\u00e1nk az adatb\u00e1zis strukt\u00far\u00e1j\u00e1t.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nMindazon\u00e1ltal nem \u00edrn\u00e1m ezt a megjegyz\u00e9st, ha nem lenn\u00e9nek h\u00e1tr\u00e1nyai az EVA haszn\u00e1lat\u00e1nak. P\u00e9ld\u00e1ul egy vagy t\u00f6bb entit\u00e1s lek\u00e9rdez\u00e9s\u00e9hez, amelyeknek 1 attrib\u00fatumuk van, 2 JOIN-ra van sz\u00fcks\u00e9g a lek\u00e9rdez\u00e9sben: az els\u0151 a tulajdons\u00e1gok t\u00e1bl\u00e1j\u00e1val val\u00f3 \u00f6sszekapcsol\u00e1s, a m\u00e1sodik az \u00e9rt\u00e9kek t\u00e1bl\u00e1j\u00e1val val\u00f3 \u00f6sszekapcsol\u00e1s. Ha az entit\u00e1snak 2 attrib\u00fatuma van, akkor m\u00e1r 4 JOIN-ra van sz\u00fcks\u00e9g! Tov\u00e1bb\u00e1 az \u00f6sszes attrib\u00fatumot \u00e1ltal\u00e1ban sz\u00f6vegk\u00e9nt t\u00e1rolj\u00e1k, ami t\u00edpuskonverzi\u00f3hoz vezet, mint az eredm\u00e9ny, \u00fagy a WHERE felt\u00e9tel eset\u00e9ben is. Ha sok lek\u00e9rdez\u00e9st \u00edrsz, akkor ez el\u00e9g pazarl\u00f3 er\u0151forr\u00e1s-haszn\u00e1lat szempontj\u00e1b\u00f3l.<\/p>\n<p>Ezek nyilv\u00e1nval\u00f3 h\u00e1tr\u00e1nyok ellen\u00e9re az EAV r\u00e9g\u00f3ta haszn\u00e1lj\u00e1k az ilyen t\u00edpus\u00fa probl\u00e9m\u00e1k megold\u00e1s\u00e1ra. Ezek elker\u00fclhetetlen h\u00e1tr\u00e1nyok voltak, \u00e9s egyszer\u0171en nem volt jobb alternat\u00edva. <br \/>\nDe ezut\u00e1n a PostgreSQL-ben megjelent egy \u00faj \u201etechnol\u00f3gia\u201d...<\/p>\n<p>A PostgreSQL 9.4-t\u0151l a JSONB adat t\u00edpus ker\u00fclt bevezet\u00e9sre a JSON bin\u00e1ris adatainak t\u00e1rol\u00e1s\u00e1ra. B\u00e1r a JSON ezen form\u00e1tumban t\u00f6rt\u00e9n\u0151 t\u00e1rol\u00e1sa \u00e1ltal\u00e1ban valamivel t\u00f6bb helyet \u00e9s id\u0151t ig\u00e9nyel, mint az egyszer\u0171 sz\u00f6veges JSON, az ezzel kapcsolatos m\u0171veletek v\u00e9grehajt\u00e1sa sokkal gyorsabb. A JSONB emellett t\u00e1mogatja az indexel\u00e9st, ami m\u00e9g gyorsabb\u00e1 teszi a lek\u00e9rdez\u00e9seket.<\/p>\n<p>A JSONB adat t\u00edpus lehet\u0151v\u00e9 teszi sz\u00e1munkra, hogy a terjedelmes EAV mint\u00e1zatot egyetlen JSONB oszlop hozz\u00e1ad\u00e1s\u00e1val egyszer\u0171bben helyettes\u00edts\u00fck az entit\u00e1saink t\u00e1bl\u00e1j\u00e1ban, ami jelent\u0151sen leegyszer\u0171s\u00edti az adatb\u00e1zis tervez\u00e9s\u00e9t. De sokan \u00e1ll\u00edtj\u00e1k, hogy ez teljes\u00edtm\u00e9nycs\u00f6kken\u00e9ssel j\u00e1rhat\u2026 Ez az ok vezetett ehhez a cikkhez.<\/p>\n<h3>Tesztadatb\u00e1zis be\u00e1ll\u00edt\u00e1sa<\/h3>\n<p>\nEhhez az \u00f6sszehasonl\u00edt\u00e1shoz egy adatb\u00e1zist hoztam l\u00e9tre egy \u00faj PostgreSQL 9.5-\u00f6s telep\u00edt\u00e9sen egy 80 doll\u00e1ros konfigur\u00e1ci\u00f3n. <noindex><a rel=\"nofollow\" href=\"https:\/\/www.digitalocean.com\/\">DigitalOcean<\/a><\/noindex> Ubuntu 14.04. N\u00e9h\u00e1ny param\u00e9ter be\u00e1ll\u00edt\u00e1sa ut\u00e1n a postgresql.conf-ban elind\u00edtottam <noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/coussej\/80c385332ce37df6687f\">az<\/a><\/noindex> a scriptet a psql seg\u00edts\u00e9g\u00e9vel. Az EAV forma megjelen\u00edt\u00e9se \u00e9rdek\u00e9ben a k\u00f6vetkez\u0151 t\u00e1bl\u00e1kat hoztuk l\u00e9tre:<\/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>\nAz al\u00e1bbi t\u00e1bl\u00e1zat tartalmazza majd ugyanazokat az adatokat, de a JSONB t\u00edpus\u00fa oszlopban l\u00e9v\u0151 attrib\u00fatumokkal \u2013 <i>itt sz\u00fcks\u00e9ges ahhoz, hogy az adminisztr\u00e1tor \u00e9rtes\u00edt\u00e9st kapjon a build \u00e9s tesztel\u00e9si eredm\u00e9nyekr\u0151l, mint a folyamat tulajdonosa.<\/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>\nEz sokkal egyszer\u0171bben n\u00e9z ki, nemde? Ezut\u00e1n 10 milli\u00f3 rekord ker\u00fclt be a t\u00f6bb entit\u00e1s t\u00e1bl\u00e1ba (<i>entity<\/i> &amp; <i>entity_jsonb<\/i>) \u00e9s megfelel\u0151en kit\u00f6lt\u00f6tt\u00fck ugyanazokkal az adatokkal az EAV mint\u00e1zatot \u00e9s a JSONB oszlopot haszn\u00e1l\u00f3 t\u00e1bl\u00e1kat \u2013 <i>entity_jsonb.properties<\/i>. \u00cdgy n\u00e9h\u00e1ny k\u00fcl\u00f6nb\u00f6z\u0151 adatt\u00edpust kaptunk az \u00f6sszes tulajdons\u00e1gk\u00e9szlet k\u00f6z\u00f6tt. P\u00e9lda az adatokra:<\/p>\n<pre><code class=\"json\">{\n  id:          1\n  name:        \"Entity1\"\n  description: \"Teszt entit\u00e1s 1. sz\u00e1ma\"\n  properties:  {\n    color:        \"piros\"\n    length:       120\n    width:        3.1882420\n    hassomething: true\n    country:      \"Belgium\"\n  } \n}<\/code><\/pre>\n<p>\n\u00cdgy most ugyanazok az adatok \u00e1llnak rendelkez\u00e9s\u00fcnkre a k\u00e9t v\u00e1ltozathoz. Kezdj\u00fck el \u00f6sszehasonl\u00edtani az implement\u00e1ci\u00f3k m\u0171k\u00f6d\u00e9s\u00e9t!<\/p>\n<h3>A diz\u00e1jn egyszer\u0171s\u00edt\u00e9se<\/h3>\n<p>\nKor\u00e1bban m\u00e1r eml\u00edtettem, hogy az adatb\u00e1zis diz\u00e1jnja jelent\u0151sen leegyszer\u0171s\u00f6d\u00f6tt: egy t\u00e1bl\u00e1zat, az EAV h\u00e1rom t\u00e1bl\u00e1ja helyett a JSONB oszlop haszn\u00e1lat\u00e1val a tulajdons\u00e1gokhoz. De hogyan hat ez a lek\u00e9rdez\u00e9sekre? Egy entit\u00e1s egy tulajdons\u00e1g\u00e1nak friss\u00edt\u00e9se \u00edgy n\u00e9z ki:<\/p>\n<pre><code class=\"pgsql\">-- EAV\nUPDATE entity_attribute_value \nSET value = 'k\u00e9k' \nWHERE entity_attribute_id = 1 \n  AND entity_id = 120;\n\n-- JSONB\nUPDATE entity_jsonb \nSET properties = jsonb_set(properties, '{\"sz\u00edn\"}', '\"k\u00e9k\"') \nWHERE id = 120;\n<\/code><\/pre>\n<p>\nAhogy l\u00e1tjuk, az utols\u00f3 lek\u00e9rdez\u00e9s nem t\u0171nik egyszer\u0171bbnek. Az \u00e9rt\u00e9k friss\u00edt\u00e9s\u00e9hez a JSONB objektumban haszn\u00e1lnunk kell a funkci\u00f3t <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.5\/static\/functions-json.html\">jsonb_set()<\/a><\/noindex>, \u00e9s az \u00faj \u00e9rt\u00e9ket JSONB objektumk\u00e9nt kell \u00e1tadnunk. Mindazon\u00e1ltal nem kell el\u0151re tudnunk semmilyen azonos\u00edt\u00f3t. Az EAV p\u00e9ld\u00e1j\u00e1ra n\u00e9zve tudnunk kell mind az entity_id-t, mind az entity_attribute_id-t a friss\u00edt\u00e9si m\u0171velet v\u00e9grehajt\u00e1s\u00e1hoz. Ha olyan tulajdons\u00e1got szeretn\u00e9nk friss\u00edteni a JSONB oszlopban, amelynek neve ismert, azt egy egyszer\u0171 sorban elv\u00e9gezhetj\u00fck.<\/p>\n<p>Most v\u00e1lasszuk ki azt az entit\u00e1st, amelyet \u00e9ppen friss\u00edtett\u00fcnk, az \u00faj sz\u00edne alapj\u00e1n:<\/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 = 'sz\u00edn' AND eav.value = 'k\u00e9k';\n\n-- JSONB\nSELECT name \nFROM entity_jsonb \nWHERE properties -&gt;&gt; 'sz\u00edn' = 'k\u00e9k';\n<\/code><\/pre>\n<p>\nAzt hiszem, egyet\u00e9rthet\u00fcnk abban, hogy a m\u00e1sodik megold\u00e1s r\u00f6videbb (nincs join!), \u00e9s \u00edgy olvashat\u00f3bb is. Itt a JSONB gy\u0151z! Az JSON oper\u00e1tort haszn\u00e1ljuk -&gt;&gt; a sz\u00edn sz\u00f6veges \u00e9rt\u00e9k\u00e9nek lek\u00e9r\u00e9s\u00e9re a JSONB objektumb\u00f3l. Van egy m\u00e1sodik m\u00f3dszer is, amellyel ugyanazt az eredm\u00e9nyt \u00e9rhetj\u00fck el a JSONB modellel a @&gt; oper\u00e1tor haszn\u00e1lat\u00e1val:<\/p>\n<pre><code class=\"pgsql\">-- JSONB \nSELECT name \nFROM entity_jsonb \nWHERE properties @&gt; '{\"sz\u00edn\": \"k\u00e9k\"}';\n<\/code><\/pre>\n<p>\nEz egy kicsit bonyolultabb: ellen\u0151rizz\u00fck, hogy a JSON objektum a properties oszlopban tartalmazza-e az objektumot, amely a @&gt; oper\u00e1tor jobb oldal\u00e1n tal\u00e1lhat\u00f3. Kev\u00e9sb\u00e9 olvashat\u00f3, de hat\u00e9konyabb (l\u00e1sd lentebb). <\/p>\n<p>M\u00e9g tov\u00e1bb egyszer\u0171s\u00edthetj\u00fck a JSONB haszn\u00e1lat\u00e1t, amikor egyszerre t\u00f6bb tulajdons\u00e1got kell kiv\u00e1lasztanunk. Itt val\u00f3ban j\u00f3l m\u0171k\u00f6dik a JSONB megk\u00f6zel\u00edt\u00e9s: egyszer\u0171en v\u00e1lasztjuk ki a tulajdons\u00e1gokat tov\u00e1bbi oszlopokk\u00e9nt az eredm\u00e9nyhalmazban an\u00e9lk\u00fcl, hogy csatlakoz\u00e1sokra lenne sz\u00fcks\u00e9g:<\/p>\n<pre><code class=\"pgsql\">-- JSONB \nSELECT name\n  , properties -&gt;&gt; 'sz\u00edn'\n  , properties -&gt;&gt; 'orsz\u00e1g'\nFROM entity_jsonb \nWHERE id = 120;\n<\/code><\/pre>\n<p>\nEAV-n\u00e1l 2 csatlakoz\u00e1sra van sz\u00fcks\u00e9ge minden egyes tulajdons\u00e1ghoz, amelyet le szeretne k\u00e9rdezni. V\u00e9lem\u00e9nyem szerint a fenti lek\u00e9rdez\u00e9sek jelent\u0151s egyszer\u0171s\u00edt\u00e9st mutatnak a adatb\u00e1zis tervez\u00e9s\u00e9ben. Tov\u00e1bbi p\u00e9ld\u00e1kat tal\u00e1lhat a JSONB lek\u00e9rdez\u00e9sek \u00edr\u00e1s\u00e1ra a <noindex><a rel=\"nofollow\" href=\"http:\/\/schinckel.net\/2014\/05\/25\/querying-json-in-postgres\/\">mell\u00e9kelt<\/a><\/noindex> bejegyz\u00e9sben.<br \/>\nMost itt az id\u0151, hogy a teljes\u00edtm\u00e9nyr\u0151l besz\u00e9lj\u00fcnk.<\/p>\n<h3>Teljes\u00edtm\u00e9ny<\/h3>\n<p>\nA teljes\u00edtm\u00e9ny \u00f6sszehasonl\u00edt\u00e1s\u00e1ra haszn\u00e1ltam <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/sql-explain.html\">EXPLAIN ANALYZE<\/a><\/noindex> A lek\u00e9rdez\u00e9sek sor\u00e1n, a v\u00e9grehajt\u00e1si id\u0151 sz\u00e1m\u00edt\u00e1sa \u00e9rdek\u00e9ben. Minden lek\u00e9rdez\u00e9s legal\u00e1bb h\u00e1romszor v\u00e9grehajt\u00f3dott, mert az els\u0151 alkalommal a lek\u00e9rdez\u00e9s-\u00fctemez\u0151nek t\u00f6bb id\u0151re van sz\u00fcks\u00e9ge. El\u0151sz\u00f6r indexek n\u00e9lk\u00fcl hajtottam v\u00e9gre a lek\u00e9rdez\u00e9seket. Nyilv\u00e1nval\u00f3, hogy ez el\u0151ny\u00f6s volt a JSONB sz\u00e1m\u00e1ra, mivel a EAV-hoz sz\u00fcks\u00e9ges joinok nem tudt\u00e1k haszn\u00e1lni az indexeket (a k\u00fcls\u0151 kulcs mez\u0151k nem voltak indexelve). Ezt k\u00f6vet\u0151en l\u00e9trehoztam egy indexet a k\u00e9t k\u00fcls\u0151 kulcs mez\u0151r\u0151l az EAV \u00e9rt\u00e9kt\u00e1bl\u00e1ban, valamint indexet <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/textsearch-indexes.html\">GIN<\/a><\/noindex> a JSONB mez\u0151h\u00f6z.<\/p>\n<p>Az adatok friss\u00edt\u00e9se a k\u00f6vetkez\u0151 id\u0151eredm\u00e9nyeket mutatta (ms-ben). Vegye figyelembe, hogy a sk\u00e1la logaritmikus:<\/p>\n<p><img decoding=\"async\" alt=\"EAV helyettes\u00edt\u00e9se JSONB-ra PostgreSQL-ben\" src=\"\/wp-content\/uploads\/2019\/11\/8a12ccd7a46d04868b1cc5fcaf01a581.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nL\u00e1that\u00f3, hogy a JSONB sokkal (&gt; 50000-szer) gyorsabb, mint az EAV, ha nem haszn\u00e1lunk indexeket, a fent eml\u00edtett ok miatt. Amikor az els\u0151dleges kulcsokkal indexelj\u00fck a mez\u0151ket, a k\u00fcl\u00f6nbs\u00e9g majdnem elt\u0171nik, de a JSONB m\u00e9g mindig 1,3-szor gyorsabb, mint az EAV. \u00c9szrevett\u00e9k, hogy a JSONB mez\u0151 indexe itt nem gyakorol semmilyen hat\u00e1st, mivel nem haszn\u00e1ljuk a tulajdons\u00e1g mez\u0151t az \u00e9rt\u00e9kel\u00e9si krit\u00e9riumok k\u00f6z\u00f6tt. <\/p>\n<p>A tulajdons\u00e1g\u00e9rt\u00e9k alapj\u00e1n t\u00f6rt\u00e9n\u0151 adatlek\u00e9rdez\u00e9s\u00fcnk a k\u00f6vetkez\u0151 eredm\u00e9nyeket adta (norm\u00e1l sk\u00e1l\u00e1n):<\/p>\n<p><img decoding=\"async\" alt=\"EAV helyettes\u00edt\u00e9se JSONB-ra PostgreSQL-ben\" src=\"\/wp-content\/uploads\/2019\/11\/e9a1fd797ef60132e661da686f6214a3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMeg lehetett figyelni, hogy a JSONB ism\u00e9t gyorsabban m\u0171k\u00f6dik, mint az EAV indexek n\u00e9lk\u00fcl, de amikor az EAV-nak indexei vannak \u2013 akkor az m\u00e9g mindig gyorsabban m\u0171k\u00f6dik, mint a JSONB. De k\u00e9s\u0151bb \u00e9szrevettem, hogy a JSONB lek\u00e9rdez\u00e9sek ideje azonos volt, ami arra k\u00e9sztetett, hogy a GIN-indexek nem m\u0171k\u00f6dnek. \u00dagy t\u0171nik, hogy amikor GIN indexet haszn\u00e1lunk a kit\u00f6lt\u00f6tt tulajdons\u00e1gok mez\u0151j\u00e9hez, az csak a @&gt; oper\u00e1tor haszn\u00e1lata eset\u00e9n m\u0171k\u00f6dik. Ezt haszn\u00e1ltam egy \u00faj tesztben, ami hatalmas hat\u00e1ssal volt az id\u0151re: csup\u00e1n 0,153 ms! Ez 15000-szer gyorsabb, mint az EAV, \u00e9s 25000-szer gyorsabb, mint a -&gt;&gt; oper\u00e1tor. <\/p>\n<p>Azt hiszem, ez el\u00e9g gyors volt!<\/p>\n<h3>Az adatb\u00e1zis t\u00e1bl\u00e1k m\u00e9rete<\/h3>\n<p>\nN\u00e9zz\u00fck meg a t\u00e1bl\u00e1k m\u00e9reteit mindk\u00e9t megk\u00f6zel\u00edt\u00e9s eset\u00e9n. A psql-ben meg tudjuk mutatni az \u00f6sszes t\u00e1bla \u00e9s index m\u00e9ret\u00e9t a k\u00f6vetkez\u0151 parancs seg\u00edts\u00e9g\u00e9vel <b>dti+<\/b><\/p>\n<p><img decoding=\"async\" alt=\"EAV helyettes\u00edt\u00e9se JSONB-ra PostgreSQL-ben\" src=\"\/wp-content\/uploads\/2019\/11\/c6c1fe7901fe9ae2bd446cf4ae99b923.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAz EAV megk\u00f6zel\u00edt\u00e9s eset\u00e9n a t\u00e1bl\u00e1k m\u00e9rete k\u00f6r\u00fclbel\u00fcl 3068 MB, m\u00edg az indexek 3427 MB-ig terjednek, ami \u00f6sszesen 6,43 GB. A JSONB megk\u00f6zel\u00edt\u00e9s alkalmaz\u00e1sakor a t\u00e1bla m\u00e9rete 1817 MB, m\u00edg az indexek\u00e9 318 MB, ami 2,08 GB-t jelent. Ez h\u00e1romszor kevesebb! Ez a t\u00e9ny kiss\u00e9 meglepett, mert a tulajdons\u00e1gneveket minden JSONB objektumban t\u00e1roljuk. <\/p>\n<p>De a sz\u00e1mok maguk\u00e9rt besz\u00e9lnek: az EAV-ban 2 eg\u00e9sz sz\u00e1m\u00fa k\u00fcls\u0151 kulcsot t\u00e1rolunk a tulajdons\u00e1g \u00e9rt\u00e9k\u00e9re, ennek eredm\u00e9nyek\u00e9nt 8 b\u00e1jt extra adatot kapunk. Ezen k\u00edv\u00fcl az EAV-ban az \u00f6sszes tulajdons\u00e1g \u00e9rt\u00e9ke sz\u00f6veg form\u00e1j\u00e1ban van t\u00e1rolva, m\u00edg a JSONB sz\u00e1mjegyeket \u00e9s logikai \u00e9rt\u00e9keket haszn\u00e1l, ahol csak lehets\u00e9ges, ami kisebb terjedelmet eredm\u00e9nyez.<\/p>\n<h3>\u00d6sszegz\u00e9s<\/h3>\n<p>\n\u00d6sszess\u00e9g\u00e9ben \u00fagy gondolom, hogy az entit\u00e1sok tulajdons\u00e1gainak JSONB form\u00e1tumban val\u00f3 t\u00e1rol\u00e1sa jelent\u0151sen leegyszer\u0171s\u00edtheti az adatb\u00e1zis\u00e1nak tervez\u00e9s\u00e9t \u00e9s karbantart\u00e1s\u00e1t. Ha sok lek\u00e9rdez\u00e9st v\u00e9gez, akkor minden, ami egy t\u00e1bl\u00e1zatban t\u00e1rol\u00f3dik az entit\u00e1ssal, val\u00f3ban hat\u00e9konyabban m\u0171k\u00f6dik. Mivel ez megk\u00f6nny\u00edti az adatok k\u00f6z\u00f6tti interakci\u00f3t, m\u00e1r ez is el\u0151ny, de a v\u00e9gs\u0151 adatb\u00e1zis 3-szor kisebb t\u00e9rfogat\u00fa.<\/p>\n<p>A v\u00e9gzett tesztek alapj\u00e1n meg\u00e1llap\u00edthat\u00f3, hogy a teljes\u00edtm\u00e9nyvesztes\u00e9g rendk\u00edv\u00fcl csek\u00e9ly. Egyes esetekben a JSONB m\u00e9g gyorsabb is az EAV-n\u00e1l, ami m\u00e9g vonz\u00f3bb\u00e1 teszi. Ez a referencia teszt azonban term\u00e9szetesen nem fedi le az \u00f6sszes szempontot (p\u00e9ld\u00e1ul az entit\u00e1sok nagyon nagy sz\u00e1m\u00fa tulajdons\u00e1gait, a megl\u00e9v\u0151 adatok jelent\u0151s tulajdons\u00e1gn\u00f6veked\u00e9s\u00e9t...), ez\u00e9rt ha b\u00e1rmilyen javaslata van a jav\u00edt\u00e1sra, ne habozzon megosztani a megjegyz\u00e9sekben!<br \/>\n<br \/>Forr\u00e1s: <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.3 - 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\/hu\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"hu_HU\" \/>\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\/hu\/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\udd47EAV helyettes\u00edt\u00e9se JSONB-vel a PostgreSQL-ben | ProHoster","description":"TL; DR: A JSONB jelent\u0151sen egyszer\u0171s\u00edtheti az adatb\u00e1zis s\u00e9m\u00e1j\u00e1nak fejleszt\u00e9s\u00e9t an\u00e9lk\u00fcl, hogy a lek\u00e9rdez\u00e9sek teljes\u00edtm\u00e9nye cs\u00f6kkenne. Bevezet\u00e9s: Ismertess\u00fck a klasszikus p\u00e9ld\u00e1t, tal\u00e1n az egyik legr\u00e9gebbit.","canonical_url":"https:\/\/prohoster.info\/hu\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"hu_HU","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\/hu\/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\/hu\/wp-json\/wp\/v2\/posts\/52584","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/comments?post=52584"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/posts\/52584\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/media?parent=52584"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/categories?post=52584"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/tags?post=52584"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}