{"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\/pt\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","title":{"rendered":"Substitui\u00e7\u00e3o de EAV por JSONB no PostgreSQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<blockquote><p>Resumo: O JSONB pode simplificar significativamente o desenvolvimento de esquemas de banco de dados sem comprometer o desempenho das consultas.<\/p><\/blockquote>\n<p><\/p>\n<h3>Introdu\u00e7\u00e3o<\/h3>\n<p>\nVamos apresentar um exemplo cl\u00e1ssico, talvez um dos mais antigos usos em bancos de dados relacionais: temos uma entidade e precisamos armazenar certas propriedades (atributos) dessa entidade. No entanto, nem todas as inst\u00e2ncias podem ter o mesmo conjunto de propriedades, al\u00e9m disso, no futuro, pode haver a necessidade de adicionar mais propriedades.<\/p>\n<p>A maneira mais simples de resolver esse problema \u00e9 criar uma coluna na tabela do banco de dados para cada valor de propriedade e preencher apenas aquelas que s\u00e3o necess\u00e1rias para uma determinada inst\u00e2ncia da entidade. \u00d3timo! Problema resolvido\u2026 at\u00e9 o momento em que sua tabela cont\u00e9m milh\u00f5es de registros e voc\u00ea precisa adicionar uma nova entrada.<\/p>\n<p>Vamos considerar o padr\u00e3o EAV (<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Entity%E2%80%93attribute%E2%80%93value_model\">Entity-Attribute-Value<\/a><\/noindex>), que aparece com bastante frequ\u00eancia. Uma tabela cont\u00e9m as entidades (registros), outra tabela cont\u00e9m os nomes das propriedades (atributos) e a terceira tabela conecta as entidades aos seus atributos e armazena os valores desses atributos para a entidade atual. Isso permite ter diferentes conjuntos de propriedades para diferentes objetos, bem como adicionar propriedades \u201cem tempo real\u201d, sem alterar a estrutura do banco de dados.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nNo entanto, eu n\u00e3o estaria escrevendo esta nota se n\u00e3o houvesse desvantagens na abordagem que utiliza EVA. Por exemplo, para obter uma ou v\u00e1rias entidades que possuem 1 atributo, s\u00e3o necess\u00e1rios 2 joins na consulta: o primeiro \u2013 uma jun\u00e7\u00e3o com a tabela de atributos, o segundo \u2013 uma jun\u00e7\u00e3o com a tabela de valores. Se a entidade tiver 2 atributos, j\u00e1 ser\u00e3o necess\u00e1rios 4 joins! Al\u00e9m disso, todos os atributos geralmente s\u00e3o armazenados como strings, o que leva \u00e0 convers\u00e3o de tipos, tanto para o resultado quanto para a condi\u00e7\u00e3o WHERE. Se voc\u00ea estiver escrevendo muitas consultas, isso torna-se bastante dispendioso em termos de uso de recursos.<\/p>\n<p>Apesar dessas desvantagens \u00f3bvias, o EAV \u00e9 utilizado h\u00e1 muito tempo para resolver esse tipo de problema. Essas desvantagens eram inevit\u00e1veis, e n\u00e3o havia uma alternativa melhor. <br \/>\nMas ent\u00e3o surgiu uma nova \"tecnologia\" no PostgreSQL...<\/p>\n<p>A partir do PostgreSQL 9.4, foi adicionado o tipo de dado JSONB para armazenamento de dados JSON em formato bin\u00e1rio. Embora armazenar JSON nesse formato geralmente ocupe um pouco mais de espa\u00e7o e tempo do que o JSON simples em texto, a execu\u00e7\u00e3o de opera\u00e7\u00f5es com ele ocorre de maneira muito mais r\u00e1pida. Al\u00e9m disso, o JSONB suporta indexa\u00e7\u00e3o, o que torna as consultas ainda mais r\u00e1pidas.<\/p>\n<p>O tipo de dado JSONB nos permite substituir o padr\u00e3o EAV complexo ao adicionar apenas uma coluna JSONB \u00e0 nossa tabela de entidades, simplificando significativamente o design do banco de dados. No entanto, muitos afirmam que isso deve ser acompanhado por uma redu\u00e7\u00e3o no desempenho\u2026 \u00c9 por isso que este artigo surgiu.<\/p>\n<h3>Configura\u00e7\u00e3o do banco de dados de teste<\/h3>\n<p>\nPara esta compara\u00e7\u00e3o, criei um banco de dados em uma nova instala\u00e7\u00e3o do PostgreSQL 9.5 em uma configura\u00e7\u00e3o de 80 d\u00f3lares <noindex><a rel=\"nofollow\" href=\"https:\/\/www.digitalocean.com\/\">DigitalOcean<\/a><\/noindex> Ubuntu 14.04. Depois de ajustar algumas configura\u00e7\u00f5es no postgresql.conf, executei <noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/coussej\/80c385332ce37df6687f\">este<\/a><\/noindex> um script usando psql. Para representar os dados no formato EAV, as seguintes tabelas foram criadas:<\/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>\nAbaixo est\u00e1 a tabela onde os mesmos dados ser\u00e3o armazenados, mas com atributos na coluna do tipo 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>\nParece muito mais simples, n\u00e3o \u00e9? Em seguida, foram adicionados 10 milh\u00f5es de registros \u00e0s tabelas de entidades (<i>entity<\/i> &amp; <i>entity_jsonb<\/i>) e, consequentemente, as tabelas que utilizam o padr\u00e3o EAV e a abordagem com a coluna JSONB foram preenchidas com os mesmos dados \u2013 <i>entity_jsonb.properties<\/i>. Assim, obtivemos v\u00e1rios tipos diferentes de dados entre todo o conjunto de propriedades. Exemplo de dados:<\/p>\n<pre><code class=\"json\">{\n  id:          1\n  name:        \"Entity1\"\n  description: \"Entidade de teste n\u00ba 1\"\n  properties:  {\n    color:        \"red\"\n    length:       120\n    width:        3.1882420\n    hasSomething: true\n    country:      \"Belgium\"\n  } \n}<\/code><\/pre>\n<p>\nEnt\u00e3o, agora temos dados id\u00eanticos para duas op\u00e7\u00f5es. Vamos come\u00e7ar a comparar as implementa\u00e7\u00f5es em a\u00e7\u00e3o!<\/p>\n<h3>Simplifica\u00e7\u00e3o do design<\/h3>\n<p>\nJ\u00e1 foi mencionado que o design do banco de dados foi significativamente simplificado: uma tabela, devido ao uso da coluna JSONB para propriedades, em vez de usar tr\u00eas tabelas para EAV. Mas como isso reflete nas consultas? A atualiza\u00e7\u00e3o de uma propriedade da entidade se parece com isto:<\/p>\n<pre><code class=\"pgsql\">-- EAV\nUPDATE entity_attribute_value \nSET value = 'azul' \nWHERE entity_attribute_id = 1 \n  AND entity_id = 120;\n\n-- JSONB\nUPDATE entity_jsonb \nSET properties = jsonb_set(properties, '{\"color\"}', '\"azul\"') \nWHERE id = 120;\n<\/code><\/pre>\n<p>\nComo vemos, a \u00faltima consulta n\u00e3o parece mais simples. Para atualizar o valor de uma propriedade em um objeto JSONB, precisamos usar a fun\u00e7\u00e3o <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.5\/static\/functions-json.html\">jsonb_set()<\/a><\/noindex>, e devemos passar nosso novo valor como um objeto JSONB. No entanto, n\u00e3o precisamos saber nenhum identificador com anteced\u00eancia. Olhando para o exemplo com EAV, precisamos saber tanto entity_id quanto entity_attribute_id para realizar a atualiza\u00e7\u00e3o. Se voc\u00ea deseja atualizar uma propriedade na coluna JSONB com base no nome do objeto, isso \u00e9 feito em uma \u00fanica linha simples.<\/p>\n<p>Agora vamos selecionar a entidade que acabamos de atualizar, com base em sua nova cor:<\/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 = 'azul';\n\n-- JSONB\nSELECT name \nFROM entity_jsonb \nWHERE properties -&gt;&gt; 'color' = 'azul';\n<\/code><\/pre>\n<p>\nAcredito que podemos concordar que a segunda \u00e9 mais curta (sem join!), e consequentemente mais leg\u00edvel. Aqui o JSONB vence! Estamos usando o operador JSON -&gt;&gt; para obter a cor como um valor de texto do objeto JSONB. Tamb\u00e9m existe uma segunda maneira de alcan\u00e7ar o mesmo resultado no modelo JSONB usando o operador @&gt;:<\/p>\n<pre><code class=\"pgsql\">-- JSONB \nSELECT name \nFROM entity_jsonb \nWHERE properties @&gt; '{\"color\": \"azul\"}';\n<\/code><\/pre>\n<p>\nIsso \u00e9 um pouco mais complicado: verificamos se o objeto JSON na coluna de propriedades cont\u00e9m o objeto \u00e0 direita do operador @&gt;. Menos leg\u00edvel, mas mais perform\u00e1tico (veja adiante). <\/p>\n<p>Vamos simplificar ainda mais o uso de JSONB quando voc\u00ea precisa selecionar v\u00e1rias propriedades ao mesmo tempo. \u00c9 aqui que a abordagem JSONB realmente se destaca: simplesmente selecionamos as propriedades como colunas adicionais no nosso conjunto de resultados sem necessidade de jun\u00e7\u00f5es:<\/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>\nCom EAV, voc\u00ea precisar\u00e1 de 2 jun\u00e7\u00f5es para cada propriedade que deseja consultar. Na minha opini\u00e3o, as consultas acima mostram uma grande simplifica\u00e7\u00e3o no design do banco de dados. Voc\u00ea pode ver mais exemplos de como escrever consultas para JSONB tamb\u00e9m em <noindex><a rel=\"nofollow\" href=\"http:\/\/schinckel.net\/2014\/05\/25\/querying-json-in-postgres\/\">isso<\/a><\/noindex> um post.<br \/>\nAgora \u00e9 hora de falar sobre desempenho.<\/p>\n<h3>Desempenho<\/h3>\n<p>\nPara comparar o desempenho, eu usei <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/sql-explain.html\">EXPLAIN ANALYZE<\/a><\/noindex> nas consultas, para calcular o tempo de execu\u00e7\u00e3o. Cada consulta foi executada pelo menos tr\u00eas vezes, pois na primeira vez o planejador de consultas leva mais tempo. Primeiro, executei as consultas sem nenhum \u00edndice. Obviamente, isso beneficiou o JSONB, j\u00e1 que os joins necess\u00e1rios para o EAV n\u00e3o podiam usar \u00edndices (os campos de chave estrangeira n\u00e3o eram indexados). Depois disso, criei um \u00edndice para 2 colunas de chaves estrangeiras na tabela de valores EAV, al\u00e9m de um \u00edndice <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/textsearch-indexes.html\">GIN<\/a><\/noindex> para a coluna JSONB.<\/p>\n<p>As atualiza\u00e7\u00f5es de dados mostraram os seguintes resultados em termos de tempo (em ms). Observe que a escala \u00e9 logar\u00edtmica:<\/p>\n<p><img decoding=\"async\" alt=\"Substitui\u00e7\u00e3o de EAV por JSONB no PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/8a12ccd7a46d04868b1cc5fcaf01a581.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPodemos ver que o JSONB \u00e9 muito (&gt; 50000x) mais r\u00e1pido que o EAV, se n\u00e3o usarmos \u00edndices, devido ao motivo mencionado acima. Quando indexamos colunas com chaves prim\u00e1rias, a diferen\u00e7a quase desaparece, mas o JSONB ainda \u00e9 1,3 vezes mais r\u00e1pido que o EAV. Observe que o \u00edndice na coluna JSONB aqui n\u00e3o tem efeito, j\u00e1 que n\u00e3o estamos utilizando a coluna de propriedades nos crit\u00e9rios de avalia\u00e7\u00e3o. <\/p>\n<p>Para selecionar dados com base no valor da propriedade, obtemos os seguintes resultados (escala comum):<\/p>\n<p><img decoding=\"async\" alt=\"Substitui\u00e7\u00e3o de EAV por JSONB no PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/e9a1fd797ef60132e661da686f6214a3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPode-se notar que o JSONB novamente funciona mais r\u00e1pido que o EAV sem \u00edndices, mas quando o EAV tem \u00edndices, ele ainda funciona mais r\u00e1pido que o JSONB. Mas depois percebi que o tempo para as consultas JSONB era o mesmo, isso me levou \u00e0 conclus\u00e3o de que o \u00edndice GIN n\u00e3o estava sendo acionado. Aparentemente, quando voc\u00ea usa um \u00edndice GIN para uma coluna com propriedades preenchidas, ele s\u00f3 funciona ao usar o operador de inclus\u00e3o @&gt;. Eu usei isso em um novo teste, o que teve um impacto enorme no tempo: apenas 0,153 ms! Isso \u00e9 15000 vezes mais r\u00e1pido que o EAV, e 25000 vezes mais r\u00e1pido que o operador -&gt;&gt;. <\/p>\n<p>Acho que isso foi r\u00e1pido o suficiente!<\/p>\n<h3>Tamanhos das tabelas do banco de dados<\/h3>\n<p>\nVamos comparar os tamanhos das tabelas com ambas as abordagens. No psql, podemos mostrar o tamanho de todas as tabelas e \u00edndices com o comando <b>dti+<\/b><\/p>\n<p><img decoding=\"async\" alt=\"Substitui\u00e7\u00e3o de EAV por JSONB no PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/c6c1fe7901fe9ae2bd446cf4ae99b923.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPara a abordagem EAV, os tamanhos das tabelas s\u00e3o cerca de 3068 MB, e os \u00edndices at\u00e9 3427 MB, totalizando 6,43 GB. Ao usar a abordagem com JSONB, utiliza-se 1817 MB para a tabela e 318 MB para os \u00edndices, totalizando 2,08 GB. Isso resulta em 3 vezes menos! Este fato me surpreendeu um pouco, pois armazenamos os nomes das propriedades em cada objeto JSONB. <\/p>\n<p>Mas os n\u00fameros falam por si: no EAV, armazenamos 2 chaves externas inteiras para o valor do atributo, resultando em 8 bytes de dados adicionais. Al\u00e9m disso, no EAV, todos os valores das propriedades s\u00e3o armazenados como texto, enquanto o JSONB usar\u00e1 valores num\u00e9ricos e l\u00f3gicos quando poss\u00edvel, resultando em um volume menor.<\/p>\n<h3>Resultados<\/h3>\n<p>\nNo geral, acredito que armazenar as propriedades das entidades no formato JSONB pode simplificar significativamente o design e a manuten\u00e7\u00e3o do seu banco de dados. Se voc\u00ea realiza muitas consultas, tudo que est\u00e1 armazenado em uma tabela com a entidade realmente funcionar\u00e1 de forma mais eficiente. E o fato de que isso simplifica a intera\u00e7\u00e3o entre os dados j\u00e1 \u00e9 um benef\u00edcio, mas o banco de dados resultante \u00e9 3 vezes menor em volume.<\/p>\n<p>Al\u00e9m disso, com base nos testes realizados, \u00e9 poss\u00edvel concluir que as perdas de desempenho s\u00e3o muito insignificantes. Em alguns casos, o JSONB pode at\u00e9 operar mais r\u00e1pido que o EAV, o que o torna ainda melhor. No entanto, esse teste de refer\u00eancia, \u00e9 claro, n\u00e3o abrange todos os aspectos (por exemplo, entidades com um n\u00famero muito grande de propriedades, aumento significativo no n\u00famero de propriedades dos dados existentes,...), portanto, se voc\u00ea tiver sugest\u00f5es sobre como aprimorar isso, fique \u00e0 vontade para deixar nos coment\u00e1rios!<br \/>\n<br \/>Fonte: <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\/pt\/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=\"pt_PT\" \/>\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\/pt\/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\udd47Substitui\u00e7\u00e3o do EAV por JSONB no PostgreSQL | ProHoster","description":"TL;DR: JSONB pode simplificar significativamente o desenvolvimento de esquemas de banco de dados sem comprometer o desempenho nas consultas. Introdu\u00e7\u00e3o Vamos dar um exemplo cl\u00e1ssico, talvez um dos mais antigos.","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pt_PT","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\/pt\/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\/pt\/wp-json\/wp\/v2\/posts\/52584","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=52584"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/52584\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=52584"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=52584"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=52584"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}