{"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\/de\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","title":{"rendered":"EAV durch JSONB in PostgreSQL ersetzen","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<blockquote><p>TL; DR: JSONB kann die Entwicklung von Datenbankschemata erheblich erleichtern, ohne die Abfrageleistung zu beeintr\u00e4chtigen.<\/p><\/blockquote>\n<p><\/p>\n<h3>Einf\u00fchrung<\/h3>\n<p>\nBetrachten wir ein klassisches Beispiel, wahrscheinlich eine der \u00e4ltesten Anwendungen in der Welt der relationalen Datenbanken: Wir haben eine Entit\u00e4t und m\u00fcssen bestimmte Eigenschaften (Attribute) dieser Entit\u00e4t speichern. Doch nicht alle Instanzen k\u00f6nnen \u00fcber denselben Satz von Eigenschaften verf\u00fcgen, und zuk\u00fcnftig k\u00f6nnte es notwendig sein, weitere Eigenschaften hinzuzuf\u00fcgen.<\/p>\n<p>Der einfachste Weg, dieses Problem zu l\u00f6sen, besteht darin, f\u00fcr jede Eigenschaft einen Spalten in der Datenbanktabelle zu erstellen und nur die f\u00fcr eine bestimmte Instanz der Entit\u00e4t ben\u00f6tigten Werte auszuf\u00fcllen. Das klingt gut! Problem gel\u00f6st\u2026 bis Ihre Tabelle Millionen von Datens\u00e4tzen enth\u00e4lt und Sie eine neue Datensatz hinzuf\u00fcgen m\u00fcssen.<\/p>\n<p>Betrachten wir das EAV-Muster (<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Entity%E2%80%93attribute%E2%80%93value_model\">Entity-Attribute-Value<\/a><\/noindex>), es kommt ziemlich h\u00e4ufig vor. Eine Tabelle enth\u00e4lt Entit\u00e4ten (Datens\u00e4tze), eine andere Tabelle enth\u00e4lt die Namen der Eigenschaften (Attribute), und eine dritte Tabelle verbindet die Entit\u00e4ten mit ihren Attributen und enth\u00e4lt die Werte dieser Attribute f\u00fcr die aktuelle Entit\u00e4t. Dies erm\u00f6glicht es Ihnen, verschiedene Eigenschaften-Sets f\u00fcr unterschiedliche Objekte zu haben und Eigenschaften \u201eon the fly\u201c hinzuzuf\u00fcgen, ohne die Datenbankstrukturen zu \u00e4ndern.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\n\u0422\u0435\u043c \u043d\u0435 \u043c\u0435\u043d\u0435\u0435, \u044f \u0431\u044b \u043d\u0435 \u043f\u0438\u0441\u0430\u043b \u044d\u0442\u0443 \u0437\u0430\u043c\u0435\u0442\u043a\u0443, \u0435\u0441\u043b\u0438 \u0431\u044b \u043d\u0435 \u0431\u044b\u043b\u043e \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u043e\u0432 \u0432 \u043f\u043e\u0434\u0445\u043e\u0434\u0435 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c EVA. \u0422\u0430\u043a, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0434\u043d\u043e\u0439 \u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u043c\u0435\u044e\u0442 \u043f\u043e 1 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0443 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f 2 join&#8217;\u0430 (\u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f) \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435: \u043f\u0435\u0440\u0432\u044b\u0439 \u2013 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 \u0442\u0430\u0431\u043b\u0438\u0446\u0435\u0439 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432, \u0432\u0442\u043e\u0440\u043e\u0439 \u2013 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 \u0442\u0430\u0431\u043b\u0438\u0446\u0435\u0439 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439. \u0415\u0441\u043b\u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u0438\u043c\u0435\u044e\u0442 2 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b, \u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0443\u0436\u0435 4 join&#8217;\u0430! \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0432\u0441\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u043e\u0431\u044b\u0447\u043d\u043e \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0435 \u0441\u0442\u0440\u043e\u043a, \u0447\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u0438\u044e \u0442\u0438\u043f\u043e\u0432, \u043a\u0430\u043a \u0434\u043b\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430, \u0442\u0430\u043a \u0438 \u0434\u043b\u044f \u0443\u0441\u043b\u043e\u0432\u0438\u044f WHERE. \u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u0438\u0448\u0435\u0442\u0435 \u043c\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u0442\u043e \u044d\u0442\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0440\u0430\u0441\u0442\u043e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e, \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432.<\/p>\n<p>Trotz dieser offensichtlichen Nachteile wird EAV bereits seit langem zur L\u00f6sung solcher Probleme eingesetzt. Diese Nachteile waren unvermeidlich, und es gab einfach keine bessere Alternative. <br \/>\nDoch dann tauchte in PostgreSQL eine neue 'Technologie' auf...<\/p>\n<p>Mit PostgreSQL 9.4 wurde der Datentyp JSONB zum Speichern von bin\u00e4ren JSON-Daten eingef\u00fchrt. Obwohl das Speichern von JSON in diesem Format normalerweise etwas mehr Platz und Zeit ben\u00f6tigt als einfaches Text-JSON, erfolgen die Operationen damit deutlich schneller. Au\u00dferdem unterst\u00fctzt JSONB die Indizierung, was die Abfragen noch schneller macht.<\/p>\n<p>Der Datentyp JSONB erm\u00f6glicht es uns, das umfangreiche EAV-Muster zu ersetzen, indem wir lediglich eine JSONB-Spalte zu unserer Entit\u00e4tstabelle hinzuf\u00fcgen, was das Datenbankdesign erheblich vereinfacht. Viele behaupten jedoch, dass dies mit einem Leistungseinbruch einhergehen sollte... Aus diesem Grund entstand dieser Artikel.<\/p>\n<h3>Einrichtung der Testdatenbank<\/h3>\n<p>\nF\u00fcr diesen Vergleich habe ich eine Datenbank auf einer frischen PostgreSQL 9.5 Installation auf einem 80-Dollar-Setup erstellt. <noindex><a rel=\"nofollow\" href=\"https:\/\/www.digitalocean.com\/\">DigitalOcean<\/a><\/noindex> Ubuntu 14.04. Nach der Anpassung einiger Parameter in der postgresql.conf habe ich sie gestartet. <noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/coussej\/80c385332ce37df6687f\">diese<\/a><\/noindex> Ein Skript mit psql. Um die Daten im EAV-Format darzustellen, wurden folgende Tabellen erstellt:<\/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>\nUnten ist eine Tabelle dargestellt, in der dieselben Daten gespeichert werden, jedoch mit Attributen in einer JSONB-Spalte \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>\nSieht viel einfacher aus, oder? Dann wurden in die Entit\u00e4tstabellen (<i>entity<\/i> &amp; <i>entity_jsonb<\/i>) 10 Millionen Datens\u00e4tze eingef\u00fcgt, und entsprechend wurden dieselben Daten in den Tabellen, die das EAV-Muster und den JSONB-Spaltenansatz verwenden, vervollst\u00e4ndigt \u2013 <i>entity_jsonb.properties<\/i>. Somit haben wir verschiedene Datentypen unter der gesamten Eigenschaftensammlung erhalten. Beispielhafte Daten:<\/p>\n<pre><code class=\"json\">{\n  id:          1\n  name:        \"Entity1\"\n  description: \"Testentit\u00e4t Nr. 1\"\n  properties:  {\n    color:        \"rot\"\n    length:       120\n    width:        3.1882420\n    hasSomething: true\n    country:      \"Belgien\"\n  } \n}<\/code><\/pre>\n<p>\nSo, jetzt haben wir dieselben Daten f\u00fcr zwei Varianten. Lassen Sie uns die Implementierungen im Betrieb vergleichen!<\/p>\n<h3>Vereinfachung des Designs<\/h3>\n<p>\nBereits erw\u00e4hnt wurde, dass das Design der Datenbank erheblich vereinfacht wurde: eine Tabelle, die durch die Verwendung einer JSONB-Spalte f\u00fcr Eigenschaften ersetzt wird, anstatt drei Tabellen f\u00fcr EAV zu nutzen. Aber wie spiegelt sich das in den Abfragen wider?<\/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>\nWie wir sehen, sieht die letzte Abfrage nicht einfacher aus. Um den Wert einer Eigenschaft im JSONB-Objekt zu aktualisieren, m\u00fcssen wir die Funktion <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.5\/static\/functions-json.html\">jsonb_set()<\/a><\/noindex>, verwenden und unser neues Wert als JSONB-Objekt \u00fcbergeben. Dennoch m\u00fcssen wir keinen Identifikator im Voraus kennen. Im Beispiel mit EAV mussten wir sowohl entity_id als auch entity_attribute_id wissen, um das Update durchzuf\u00fchren. Wenn Sie eine Eigenschaft in der JSONB-Spalte basierend auf dem Objektname aktualisieren m\u00f6chten, geschieht das alles mit einer einfachen Zeile.<\/p>\n<p>Lassen Sie uns nun die Entit\u00e4t ausw\u00e4hlen, die wir gerade mit der Bedingung ihrer neuen Farbe aktualisiert haben:<\/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>\nIch denke, wir k\u00f6nnen uns darauf einigen, dass die zweite Option k\u00fcrzer ist (ohne Join!) und somit lesbarer. Hier gewinnt JSONB! Wir verwenden den JSON-Operator -&gt;&gt;, um die Farbe als Textwert aus dem JSONB-Objekt abzurufen. Es gibt auch eine zweite Methode, um dasselbe Ergebnis im JSONB-Modell mit dem Operator @&gt; zu erreichen:<\/p>\n<pre><code class=\"pgsql\">-- JSONB \nSELECT name \nFROM entity_jsonb \nWHERE properties @&gt; '{\"color\": \"blue\"}';\n<\/code><\/pre>\n<p>\nEs ist etwas komplizierter: Wir \u00fcberpr\u00fcfen, ob das JSON-Objekt in der Spalte properties das Objekt rechts vom @&gt; Operator enth\u00e4lt. Weniger lesbar, aber leistungsf\u00e4higer (siehe weiter unten). <\/p>\n<p>Lassen Sie uns die Verwendung von JSONB weiter vereinfachen, wenn Sie mehrere Eigenschaften gleichzeitig ausw\u00e4hlen m\u00fcssen. Hier spielt der JSONB-Ansatz wirklich seine St\u00e4rken aus: Wir w\u00e4hlen einfach die Eigenschaften als zus\u00e4tzliche Spalten in unserem Ergebnis-Set aus, ohne dass Joins erforderlich sind:<\/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>\nMit EAV ben\u00f6tigen Sie 2 Joins f\u00fcr jede Eigenschaft, die Sie abfragen m\u00f6chten. Meiner Meinung nach zeigen die oben aufgef\u00fchrten Abfragen eine erhebliche Vereinfachung im Datenbankdesign. Weitere Beispiele, wie man Abfragen f\u00fcr JSONB schreibt, finden Sie auch in <noindex><a rel=\"nofollow\" href=\"http:\/\/schinckel.net\/2014\/05\/25\/querying-json-in-postgres\/\">diesem<\/a><\/noindex> dem Beitrag.<br \/>\nNun ist es an der Zeit, \u00fcber die Leistung zu sprechen.<\/p>\n<h3>Leistung<\/h3>\n<p>\nUm die Leistung zu vergleichen, habe ich <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/sql-explain.html\">EXPLAIN ANALYZE<\/a><\/noindex> in den Abfragen verwendet, um die Ausf\u00fchrungszeit zu messen. Jede Abfrage wurde mindestens drei Mal ausgef\u00fchrt, da der Abfrageplaner beim ersten Mal mehr Zeit ben\u00f6tigt. Zun\u00e4chst f\u00fchrte ich die Abfragen ohne Indizes aus. Offensichtlich war dies ein Vorteil f\u00fcr JSONB, da die Joins, die f\u00fcr EAV erforderlich sind, keine Indizes nutzen konnten (die Felder der Fremdschl\u00fcssel waren nicht indiziert). Danach erstellte ich einen Index f\u00fcr die 2 Spalten der Fremdschl\u00fcssel in der EAV-Wertetabelle sowie einen Index <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/textsearch-indexes.html\">GIN<\/a><\/noindex> f\u00fcr die JSONB-Spalte.<\/p>\n<p>Datenaktualisierungen zeigten folgende Ergebnisse in Bezug auf die Zeit (in ms). Beachten Sie, dass die Skala logarithmisch ist:<\/p>\n<p><img decoding=\"async\" alt=\"EAV durch JSONB in PostgreSQL ersetzen\" src=\"\/wp-content\/uploads\/2019\/11\/8a12ccd7a46d04868b1cc5fcaf01a581.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWir sehen, dass JSONB deutlich schneller ist (&gt; 50.000 Mal) als EAV, wenn keine Indizes verwendet werden, aus dem oben genannten Grund. Wenn wir die Spalten mit Prim\u00e4rschl\u00fcsseln indizieren, verschwindet der Unterschied nahezu, aber JSONB ist immer noch 1,3 Mal schneller als EAV. Beachten Sie, dass der Index in der JSONB-Spalte hier keinen Einfluss hat, da wir die Eigenschaftsspalte nicht in den Bewertungsbedingungen verwenden. <\/p>\n<p>F\u00fcr die Auswahl von Daten basierend auf dem Wert einer Eigenschaft erhalten wir folgende Ergebnisse (\u00fcblicher Ma\u00dfstab):<\/p>\n<p><img decoding=\"async\" alt=\"EAV durch JSONB in PostgreSQL ersetzen\" src=\"\/wp-content\/uploads\/2019\/11\/e9a1fd797ef60132e661da686f6214a3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEs ist zu bemerken, dass JSONB erneut schneller funktioniert als EAV ohne Indizes. Wenn EAV jedoch Indizes hat, arbeitet es immer noch schneller als JSONB. Sp\u00e4ter bemerkte ich, dass die Zeit f\u00fcr JSONB-Abfragen gleich blieb, was mich zu dem Schluss f\u00fchrte, dass der GIN-Index nicht ausgel\u00f6st wurde. Anscheinend wirkt der GIN-Index bei einer Spalte mit ausgef\u00fcllten Eigenschaften nur, wenn der Einschlussoperator @&gt; verwendet wird. Ich habe dies in einem neuen Test verwendet, der enorme Auswirkungen auf die Zeit hatte: nur 0,153 ms! Das ist 15.000 Mal schneller als EAV und 25.000 Mal schneller als der Operator -&gt;&gt;. <\/p>\n<p>Ich denke, das war schnell genug!<\/p>\n<h3>Gr\u00f6\u00dfe der DB-Tabellen<\/h3>\n<p>\nLassen Sie uns die Tabellengr\u00f6\u00dfen bei beiden Ans\u00e4tzen vergleichen. In psql k\u00f6nnen wir die Gr\u00f6\u00dfe aller Tabellen und Indizes mit dem Befehl anzeigen <b>dti+<\/b><\/p>\n<p><img decoding=\"async\" alt=\"EAV durch JSONB in PostgreSQL ersetzen\" src=\"\/wp-content\/uploads\/2019\/11\/c6c1fe7901fe9ae2bd446cf4ae99b923.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nF\u00fcr den EAV-Ansatz betragen die Tabellengr\u00f6\u00dfen etwa 3068 MB und die Indizes bis zu 3427 MB, was insgesamt 6,43 GB ergibt. Bei Verwendung des JSONB-Ansatzes werden 1817 MB f\u00fcr die Tabelle und 318 MB f\u00fcr die Indizes verwendet, was 2,08 GB entspricht. Das ist dreimal weniger! Diese Tatsache hat mich etwas \u00fcberrascht, da wir die Eigenschaftsnamen in jedem JSONB-Objekt speichern. <\/p>\n<p>Aber die Zahlen sprechen f\u00fcr sich: Im EAV speichern wir 2 ganzzahlige Fremdschl\u00fcssel f\u00fcr den Attributwert, was zu 8 Byte zus\u00e4tzlichen Daten f\u00fchrt. Au\u00dferdem werden im EAV alle Werte als Text gespeichert, w\u00e4hrend JSONB wo m\u00f6glich numerische und boolesche Werte verwendet, was zu einem geringeren Volumen f\u00fchrt.<\/p>\n<h3>Ergebnisse<\/h3>\n<p>\nInsgesamt denke ich, dass die Beibehaltung der Eigenschaften von Entit\u00e4ten im JSONB-Format das Design und die Wartung Ihrer Datenbank erheblich vereinfachen kann. Wenn Sie viele Abfragen durchf\u00fchren, funktioniert alles, was in einer Tabelle mit der Entit\u00e4t gespeichert ist, tats\u00e4chlich effizienter. Dar\u00fcber hinaus vereinfacht es die Interaktion zwischen den Daten, was bereits einen Vorteil darstellt, und die resultierende Datenbank ist um das Drei-fache kleiner.<\/p>\n<p>Auch aus den durchgef\u00fchrten Tests l\u00e4sst sich zusammenfassen, dass die Leistungseinbu\u00dfen \u00e4u\u00dferst gering sind. In einigen F\u00e4llen arbeitet JSONB sogar schneller als EAV, was es noch vorteilhafter macht. Dieser Benchmark-Test deckt jedoch nat\u00fcrlich nicht alle Aspekte ab (z.B. Entit\u00e4ten mit einer sehr gro\u00dfen Anzahl von Eigenschaften, signifikante Zunahme der Anzahl der Eigenschaften bestehender Daten,...), daher, wenn Sie Vorschl\u00e4ge zur Verbesserung haben, z\u00f6gern Sie bitte nicht, diese in den Kommentaren zu hinterlassen!<br \/>\n<br \/>Quelle: <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 4.9.10 - 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 \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\" \/>\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\/de\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\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 \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\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/de\/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 durch JSONB in PostgreSQL ersetzen | ProHoster","description":"TL; DR: JSONB kann die Entwicklung von Datenbankschemas erheblich vereinfachen, ohne die Abfrageleistung zu beeintr\u00e4chtigen. Einleitung Ein klassisches Beispiel, wahrscheinlich eine der \u00e4ltesten Anwendungen in der Welt der relationalen Datenbanken (Datenbank): Wir haben eine Entit\u00e4t und m\u00fcssen bestimmte Eigenschaften (Attribute) dieser Entit\u00e4t speichern. Aber nicht alle Instanzen k\u00f6nnen denselben Satz von Eigenschaften haben, au\u00dferdem in","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","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 \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","og:url":"https:\/\/prohoster.info\/de\/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"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/52584","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=52584"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/52584\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=52584"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=52584"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=52584"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}