{"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\/es\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","title":{"rendered":"Reemplazo de EAV por JSONB en PostgreSQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<blockquote><p>TL; DR: JSONB puede simplificar notablemente el desarrollo de esquemas de bases de datos sin comprometer el rendimiento de las consultas.<\/p><\/blockquote>\n<p><\/p>\n<h3>Introducci\u00f3n<\/h3>\n<p>\nTomemos un ejemplo cl\u00e1sico, probablemente uno de los usos m\u00e1s antiguos del mundo de las bases de datos relacionales: tenemos una entidad y necesitamos almacenar ciertas propiedades (atributos) de esa entidad. Pero no todos los ejemplos pueden tener el mismo conjunto de propiedades, adem\u00e1s de que en el futuro podr\u00eda ser necesario agregar m\u00e1s propiedades.<\/p>\n<p>La forma m\u00e1s simple de resolver este problema es crear una columna en la tabla de la base de datos para cada valor de propiedad, y simplemente rellenar aquellas que son necesarias para un determinado ejemplo de la entidad. \u00a1Perfecto! El problema est\u00e1 resuelto... hasta que tu tabla contiene millones de registros y tienes que agregar un nuevo registro.<\/p>\n<p>Consideremos el patr\u00f3n EAV (<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Entity%E2%80%93attribute%E2%80%93value_model\">Entidad-Atributo-Valor<\/a><\/noindex>), que se encuentra con bastante frecuencia. Una tabla contiene entidades (registros), otra tabla contiene nombres de propiedades (atributos), y una tercera tabla vincula las entidades con sus atributos y contiene el valor de esos atributos para la entidad actual. Esto te permite tener diferentes conjuntos de propiedades para distintos objetos y tambi\u00e9n agregar propiedades 'sobre la marcha', sin modificar la estructura de la base de datos.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nSin embargo, no habr\u00eda escrito esta nota si no hubiera deficiencias en el enfoque que utiliza EVA. Por ejemplo, para obtener una o varias entidades que tienen un atributo, se requieren 2 joins en la consulta: el primero es la uni\u00f3n con la tabla de atributos y el segundo, la uni\u00f3n con la tabla de valores. Si la entidad tiene 2 atributos, \u00a1necesitar\u00e1s ya 4 joins! Adem\u00e1s, normalmente todos los atributos se almacenan como cadenas, lo que provoca conversiones de tipos tanto para el resultado como para la cl\u00e1usula WHERE. Si escribes muchas consultas, esto es bastante derrochador en t\u00e9rminos de uso de recursos.<\/p>\n<p>A pesar de estas desventajas evidentes, EAV ha sido utilizado durante mucho tiempo para abordar este tipo de problemas. Estos eran inconvenientes inevitables, y simplemente no hab\u00eda una mejor alternativa. <br \/>\nPero luego apareci\u00f3 una nueva 'tecnolog\u00eda' en PostgreSQL...<\/p>\n<p>A partir de PostgreSQL 9.4, se agreg\u00f3 un tipo de dato JSONB para almacenar datos binarios JSON. Aunque almacenar JSON en este formato generalmente ocupa un poco m\u00e1s de espacio y tiempo que el JSON en texto plano, las operaciones sobre \u00e9l se realizan mucho m\u00e1s r\u00e1pido. Adem\u00e1s, JSONB admite indexaci\u00f3n, lo que hace que las consultas sean a\u00fan m\u00e1s r\u00e1pidas.<\/p>\n<p>El tipo de dato JSONB nos permite reemplazar el engorroso patr\u00f3n EAV al agregar simplemente una columna JSONB a nuestra tabla de entidades, lo que simplifica significativamente el dise\u00f1o de la base de datos. Pero muchos argumentan que esto deber\u00eda ir acompa\u00f1ado de una disminuci\u00f3n en el rendimiento\u2026 Esta es la raz\u00f3n por la cual apareci\u00f3 este art\u00edculo.<\/p>\n<h3>Configuraci\u00f3n de la base de datos de prueba<\/h3>\n<p>\nPara esta comparaci\u00f3n, cre\u00e9 una base de datos en una nueva instalaci\u00f3n de PostgreSQL 9.5 en una construcci\u00f3n de 80 d\u00f3lares <noindex><a rel=\"nofollow\" href=\"https:\/\/www.digitalocean.com\/\">Encuesta<\/a><\/noindex> Ubuntu 14.04. Despu\u00e9s de ajustar algunos par\u00e1metros en postgresql.conf, ejecut\u00e9 <noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/coussej\/80c385332ce37df6687f\">este<\/a><\/noindex> el script usando psql. Para representar los datos en formato EAV se crearon las siguientes tablas:<\/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>\nA continuaci\u00f3n se muestra la tabla donde se almacenar\u00e1n los mismos datos, pero con atributos en una columna de 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>\nSe ve mucho m\u00e1s simple, \u00bfverdad? Luego se a\u00f1adieron a las tablas de entidades (<i>entity<\/i> &amp; <i>entity_jsonb<\/i>) 10 millones de registros, y por lo tanto se poblaron con los mismos datos las tablas donde se utiliza el patr\u00f3n EAV y el enfoque con la columna JSONB \u2013 <i>entity_jsonb.properties<\/i>. As\u00ed, obtuvimos varios tipos de datos entre todo el conjunto de propiedades. Ejemplo de datos:<\/p>\n<pre><code class=\"json\">{\n  id:          1\n  name:        \"Entity1\"\n  description: \"Entidad de prueba n.\u00ba 1\"\n  properties:  {\n    color:        \"rojo\"\n    length:       120\n    width:        3.1882420\n    hasSomething: true\n    country:      \"B\u00e9lgica\"\n  } \n}<\/code><\/pre>\n<p>\nAs\u00ed que ahora tenemos los mismos datos para dos variantes. \u00a1Comencemos a comparar las implementaciones en acci\u00f3n!<\/p>\n<h3>Simplificaci\u00f3n del dise\u00f1o<\/h3>\n<p>\nYa se ha mencionado que el dise\u00f1o de la base de datos se ha simplificado significativamente: una tabla, gracias al uso de la columna JSONB para las propiedades, en lugar de utilizar tres tablas para EAV. Pero, \u00bfc\u00f3mo se refleja esto en las consultas? La actualizaci\u00f3n de una propiedad de la entidad se ve as\u00ed:<\/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 podemos ver, la \u00faltima consulta no parece ser m\u00e1s sencilla. Para actualizar el valor de una propiedad en un objeto JSONB, debemos usar la funci\u00f3n <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.5\/static\/functions-json.html\">jsonb_set()<\/a><\/noindex>, y debemos pasar nuestro nuevo valor como un objeto JSONB. Sin embargo, no necesitamos conocer ning\u00fan identificador de antemano. Al observar el ejemplo con EAV, necesitamos conocer tanto entity_id como entity_attribute_id para realizar la actualizaci\u00f3n. Si deseas actualizar una propiedad en la columna JSONB bas\u00e1ndote en el nombre del objeto, esto se hace con una simple l\u00ednea.<\/p>\n<p>Ahora seleccionemos la entidad que acabamos de actualizar, de acuerdo con su nuevo 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 = 'azul';\n\n-- JSONB\nSELECT name \nFROM entity_jsonb \nWHERE properties -&gt;&gt; 'color' = 'azul';\n<\/code><\/pre>\n<p>\nCreo que podemos estar de acuerdo en que la segunda es m\u00e1s corta (sin un join), y por lo tanto m\u00e1s legible. \u00a1Aqu\u00ed JSONB gana! Usamos el operador JSON -&gt;&gt; para obtener el color como un valor de texto del objeto JSONB. Tambi\u00e9n hay una segunda manera de lograr el mismo resultado en el modelo JSONB utilizando el operador @&gt;:<\/p>\n<pre><code class=\"pgsql\">-- JSONB \nSELECT name \nFROM entity_jsonb \nWHERE properties @&gt; '{\"color\": \"azul\"}';\n<\/code><\/pre>\n<p>\nEs un poco m\u00e1s complicado: estamos verificando si el objeto JSON en la columna de propiedades contiene el objeto que est\u00e1 a la derecha del operador @&gt;. Menos legible, pero m\u00e1s eficiente (ver m\u00e1s adelante). <\/p>\n<p>Simplifiquemos a\u00fan m\u00e1s el uso de JSONB cuando necesitas seleccionar varias propiedades a la vez. Aqu\u00ed es donde realmente encaja el enfoque JSONB: simplemente seleccionamos las propiedades como columnas adicionales en nuestro conjunto de resultados sin necesidad de uniones:<\/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>\nCon EAV necesitar\u00e1s 2 uniones para cada propiedad que desees consultar. En mi opini\u00f3n, las consultas anteriores muestran una gran simplificaci\u00f3n en el dise\u00f1o de la base de datos. Tambi\u00e9n puedes ver m\u00e1s ejemplos de c\u00f3mo escribir consultas para JSONB en <noindex><a rel=\"nofollow\" href=\"http:\/\/schinckel.net\/2014\/05\/25\/querying-json-in-postgres\/\">este<\/a><\/noindex> la publicaci\u00f3n.<br \/>\nAhora es momento de hablar sobre el rendimiento.<\/p>\n<h3>Rendimiento<\/h3>\n<p>\nPara comparar el rendimiento, utilic\u00e9 <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/sql-explain.html\">EXPLAIN ANALYZE<\/a><\/noindex> en las consultas, para calcular el tiempo de ejecuci\u00f3n. Cada consulta se ejecut\u00f3 al menos tres veces, ya que la primera vez el planificador de consultas requiere m\u00e1s tiempo. Primero ejecut\u00e9 las consultas sin ning\u00fan \u00edndice. Obviamente, esto benefici\u00f3 a JSONB, ya que las uniones necesarias para EAV no pod\u00edan utilizar \u00edndices (los campos de clave externa no estaban indexados). Despu\u00e9s de eso, cre\u00e9 un \u00edndice para las 2 columnas de claves externas en la tabla de valores EAV, as\u00ed como un \u00edndice <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/textsearch-indexes.html\">GIN<\/a><\/noindex> para la columna JSONB.<\/p>\n<p>Las actualizaciones de datos mostraron los siguientes resultados de tiempo (en ms). Tenga en cuenta que la escala es logar\u00edtmica:<\/p>\n<p><img decoding=\"async\" alt=\"Reemplazo de EAV por JSONB en PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/8a12ccd7a46d04868b1cc5fcaf01a581.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nVemos que JSONB es mucho (&gt; 50000 veces) m\u00e1s r\u00e1pido que EAV, si no se utilizan \u00edndices, por la raz\u00f3n mencionada anteriormente. Cuando indexamos las columnas con claves primarias, la diferencia casi desaparece, pero JSONB sigue siendo 1,3 veces m\u00e1s r\u00e1pido que EAV. Tenga en cuenta que el \u00edndice en la columna JSONB aqu\u00ed no tiene ning\u00fan efecto, ya que no utilizamos la columna de propiedades en los criterios de evaluaci\u00f3n. <\/p>\n<p>Para seleccionar datos basados en el valor de la propiedad, obtenemos los siguientes resultados (escala normal):<\/p>\n<p><img decoding=\"async\" alt=\"Reemplazo de EAV por JSONB en PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/e9a1fd797ef60132e661da686f6214a3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSe puede notar que JSONB nuevamente funciona m\u00e1s r\u00e1pido que EAV sin \u00edndices, pero cuando EAV tiene \u00edndices, todav\u00eda funciona m\u00e1s r\u00e1pido que JSONB. Pero luego vi que el tiempo para las consultas JSONB era el mismo, esto me llev\u00f3 a la conclusi\u00f3n de que los \u00edndices GIN no estaban activ\u00e1ndose. Al parecer, cuando se utiliza un \u00edndice GIN para una columna con propiedades llenas, act\u00faa solo cuando se utiliza el operador de inclusi\u00f3n @&gt;. Utilic\u00e9 esto en una nueva prueba, lo cual tuvo un impacto enorme en el tiempo: \u00a1solo 0,153 ms! Esto es 15000 veces m\u00e1s r\u00e1pido que EAV y 25000 veces m\u00e1s r\u00e1pido que el operador -&gt;&gt;. <\/p>\n<p>Creo que fue bastante r\u00e1pido.<\/p>\n<h3>Tama\u00f1o de las tablas de la base de datos<\/h3>\n<p>\nComparamos los tama\u00f1os de las tablas entre ambos enfoques. En psql podemos mostrar el tama\u00f1o de todas las tablas e \u00edndices con el comando <b>dti+<\/b><\/p>\n<p><img decoding=\"async\" alt=\"Reemplazo de EAV por JSONB en PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/c6c1fe7901fe9ae2bd446cf4ae99b923.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPara el enfoque EAV, el tama\u00f1o de las tablas es de aproximadamente 3068 MB, y los \u00edndices hasta 3427 MB, lo que suma 6,43 GB. Al utilizar el enfoque con JSONB, se utilizan 1817 MB para la tabla y 318 MB para los \u00edndices, lo que equivale a 2,08 GB. \u00a1Es tres veces menos! Este hecho me sorprendi\u00f3 un poco, ya que almacenamos los nombres de las propiedades en cada objeto JSONB. <\/p>\n<p>Pero los n\u00fameros hablan por s\u00ed mismos: en EAV almacenamos 2 claves externas enteras para el valor del atributo, lo que resulta en 8 bytes de datos adicionales. Adem\u00e1s, en EAV todos los valores de las propiedades se almacenan como texto, mientras que JSONB utilizar\u00e1 valores num\u00e9ricos y l\u00f3gicos internamente siempre que sea posible, lo que da como resultado un menor volumen.<\/p>\n<h3>Resultados<\/h3>\n<p>\nEn general, creo que almacenar las propiedades de las entidades en formato JSONB puede simplificar significativamente el dise\u00f1o y mantenimiento de su base de datos. Si realiza muchas consultas, todo lo que se almacena en una tabla junto a la entidad realmente funcionar\u00e1 de manera m\u00e1s eficiente. Y el hecho de que simplifique la interacci\u00f3n entre los datos ya es un beneficio, pero adem\u00e1s la base de datos resultante es 3 veces m\u00e1s peque\u00f1a en volumen.<\/p>\n<p>Adem\u00e1s, seg\u00fan las pruebas realizadas, se puede concluir que las p\u00e9rdidas de rendimiento son muy insignificantes. En algunos casos, JSONB incluso funciona m\u00e1s r\u00e1pido que EAV, lo que lo hace a\u00fan mejor. Sin embargo, esta prueba de referencia, por supuesto, no cubre todos los aspectos (por ejemplo, entidades con un n\u00famero muy grande de propiedades, un aumento significativo en el n\u00famero de propiedades de los datos existentes,\u2026), por lo que si tiene alguna sugerencia sobre c\u00f3mo mejorarlas, no dude en dejar sus comentarios.<br \/>\n<br \/>Fuente: <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\/es\/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=\"es_ES\" \/>\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\/es\/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\udd47Sustituci\u00f3n de EAV por JSONB en PostgreSQL | ProHoster","description":"TL; DR: JSONB puede simplificar significativamente el desarrollo del esquema de la base de datos sin afectar el rendimiento de las consultas. Introducci\u00f3n Presentamos un ejemplo cl\u00e1sico, probablemente uno de los m\u00e1s antiguos.","canonical_url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"es_ES","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\/es\/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\/es\/wp-json\/wp\/v2\/posts\/52584","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/comments?post=52584"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/52584\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media?parent=52584"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/categories?post=52584"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/tags?post=52584"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}