{"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\/it\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","title":{"rendered":"Sostituzione di EAV con JSONB in PostgreSQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<blockquote><p>TL; DR: JSONB pu\u00f2 semplificare notevolmente lo sviluppo dello schema del database senza compromettere le prestazioni delle query.<\/p><\/blockquote>\n<p><\/p>\n<h3>Introduzione<\/h3>\n<p>\nFacciamo un esempio classico, probabilmente uno dei pi\u00f9 antichi casi d'uso nel mondo dei database relazionali: abbiamo un'entit\u00e0 e dobbiamo memorizzare alcune propriet\u00e0 (attributi) di questa entit\u00e0. Tuttavia, non tutti gli oggetti possono avere lo stesso insieme di propriet\u00e0 e, inoltre, in futuro potrebbe essere necessario aggiungere ulteriori propriet\u00e0.<\/p>\n<p>Il modo pi\u00f9 semplice per risolvere questo problema \u00e8 creare una colonna nella tabella del database per ogni valore di propriet\u00e0 e semplicemente compilare quelle necessarie per un determinato oggetto. Ottimo! Problema risolto... fino a quando la vostra tabella non contiene milioni di record e non avete bisogno di aggiungere una nuova registrazione.<\/p>\n<p>Consideriamo il pattern EAV (<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Entity%E2%80%93attribute%E2%80%93value_model\">Entity-Attribute-Value<\/a><\/noindex>), che si incontra abbastanza spesso. Una tabella contiene entit\u00e0 (record), un'altra tabella contiene i nomi delle propriet\u00e0 (attributi), e una terza tabella collega le entit\u00e0 ai loro attributi e contiene il valore di questi attributi per l'entit\u00e0 attuale. Questo ti consente di avere set di propriet\u00e0 diversi per oggetti differenti e di aggiungere propriet\u00e0 \"al volo\", senza modificare la struttura del database.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nTuttavia, non scriverei questa nota se non ci fossero difetti nell'approccio che utilizza EVA. Ad esempio, per ottenere una o pi\u00f9 entit\u00e0 che hanno 1 attributo, sono necessari 2 join nella query: il primo \u00e8 un'unione con la tabella degli attributi, il secondo \u00e8 un'unione con la tabella dei valori. Se l'entit\u00e0 ha 2 attributi, servono gi\u00e0 4 join! Inoltre, tutti gli attributi sono solitamente memorizzati come stringhe, il che comporta conversioni di tipo, sia per i risultati che per la condizione WHERE. Se si scrivono molte query, questo \u00e8 abbastanza dispendioso in termini di utilizzo delle risorse.<\/p>\n<p>Nonostante questi evidenti svantaggi, l'EAV \u00e8 gi\u00e0 da tempo utilizzato per affrontare questo tipo di problemi. Questi erano difetti inevitabili e non c'era semplicemente una migliore alternativa. <br \/>\nMa poi in PostgreSQL \u00e8 emersa una nuova \"tecnologia\"...<\/p>\n<p>A partire da PostgreSQL 9.4, \u00e8 stato aggiunto il tipo di dato JSONB per conservare dati JSON binari. Sebbene la memorizzazione dei JSON in questo formato richieda solitamente un po' pi\u00f9 di spazio e tempo rispetto al JSON in formato testo semplice, l'esecuzione delle operazioni su di esso avviene molto pi\u00f9 rapidamente. Inoltre, JSONB supporta l'indicizzazione, il che rende le query su di esso ancora pi\u00f9 veloci.<\/p>\n<p>Il tipo di dato JSONB ci consente di sostituire il pesante schema EAV semplicemente aggiungendo una sola colonna JSONB alla nostra tabella delle entit\u00e0, semplificando notevolmente il design del database. Tuttavia, molti sostengono che ci\u00f2 debba comportare una riduzione delle prestazioni\u2026 \u00c8 per questo motivo che \u00e8 nato questo articolo.<\/p>\n<h3>Impostazione del database di test<\/h3>\n<p>\nPer questo confronto ho creato un database su una nuova installazione di PostgreSQL 9.5 su un'installazione da 80 dollari <noindex><a rel=\"nofollow\" href=\"https:\/\/www.digitalocean.com\/\">DigitalOcean<\/a><\/noindex> Ubuntu 14.04. Dopo aver configurato alcuni parametri in postgresql.conf, ho eseguito <noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/coussej\/80c385332ce37df6687f\">questo<\/a><\/noindex> uno script utilizzando psql. Per rappresentare i dati in formato EAV sono state create le seguenti tabelle:<\/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>\nDi seguito \u00e8 riportata una tabella in cui verranno memorizzati gli stessi dati, ma con gli attributi in una colonna di 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>\nSembra molto pi\u00f9 semplice, non \u00e8 vero? Poi sono state aggiunte alle tabelle delle entit\u00e0 (<i>entity<\/i> &amp; <i>entity_jsonb<\/i>) 10 milioni di record, e di conseguenza, sono stati riempiti con gli stessi dati le tabelle dove si utilizza lo schema EAV e l'approccio con la colonna JSONB \u2013 <i>entity_jsonb.properties<\/i>. Cos\u00ec abbiamo ottenuto diversi tipi di dati tra l'insieme di propriet\u00e0. Esempio di dati:<\/p>\n<pre><code class=\"json\">{\n  id:          1\n  name:        \"Entity1\"\n  description: \"Entit\u00e0 di test n. 1\"\n  properties:  {\n    color:        \"rosso\"\n    lenght:       120\n    width:        3.1882420\n    hassomething: true\n    country:      \"Belgio\"\n  } \n}<\/code><\/pre>\n<p>\nQuindi ora abbiamo dati identici per le due varianti. Iniziamo a confrontare le implementazioni in azione!<\/p>\n<h3>Semplificazione del design<\/h3>\n<p>\n\u00c8 stato gi\u00e0 detto in precedenza che il design del database \u00e8 stato notevolmente semplificato: una tabella, grazie all'uso della colonna JSONB per le propriet\u00e0, invece di utilizzare tre tabelle per EAV. Ma come si riflette questo nelle query? L'aggiornamento di una propriet\u00e0 dell'entit\u00e0 si presenta come segue:<\/p>\n<pre><code class=\"pgsql\">-- EAV\nUPDATE entity_attribute_value \nSET value = 'blu' \nWHERE entity_attribute_id = 1 \n  AND entity_id = 120;\n\n-- JSONB\nUPDATE entity_jsonb \nSET properties = jsonb_set(properties, '{\"color\"}', '\"blu\"') \nWHERE id = 120;\n<\/code><\/pre>\n<p>\nCome vediamo, l'ultima query non sembra pi\u00f9 semplice. Per aggiornare il valore di una propriet\u00e0 in un oggetto JSONB, dobbiamo utilizzare la funzione <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.5\/static\/functions-json.html\">jsonb_set()<\/a><\/noindex>, e dobbiamo passare il nostro nuovo valore come oggetto JSONB. Tuttavia, non dobbiamo conoscere alcun identificatore in anticipo. Guardando l'esempio con EAV, dobbiamo conoscere sia l'entity_id che l'entity_attribute_id per eseguire l'aggiornamento. Se vuoi aggiornare una propriet\u00e0 nella colonna JSONB basandoti sul nome dell'oggetto, tutto questo si fa in una semplice riga.<\/p>\n<p>Ora scegliamo l'entit\u00e0 che abbiamo appena aggiornato, in base al suo nuovo colore:<\/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 = 'blu';\n\n-- JSONB\nSELECT name \nFROM entity_jsonb \nWHERE properties -&gt;&gt; 'color' = 'blu';\n<\/code><\/pre>\n<p>\nCredo che possiamo concordare sul fatto che il secondo \u00e8 pi\u00f9 corto (senza join!), e quindi pi\u00f9 leggibile. Qui vince JSONB! Utilizziamo l'operatore JSON -&gt;&gt; per ottenere il colore come valore di testo dall'oggetto JSONB. Esiste anche un secondo modo per ottenere lo stesso risultato nel modello JSONB utilizzando l'operatore @&gt;:<\/p>\n<pre><code class=\"pgsql\">-- JSONB \nSELECT name \nFROM entity_jsonb \nWHERE properties @&gt; '{\"color\": \"blu\"}';\n<\/code><\/pre>\n<p>\nQuesto \u00e8 un po' pi\u00f9 complicato: stiamo verificando se l'oggetto JSON nella colonna delle propriet\u00e0 contiene l'oggetto che si trova a destra dell'operatore @&gt;. Meno leggibile, pi\u00f9 performante (vedi oltre). <\/p>\n<p>Semplifichiamo ulteriormente l'uso di JSONB quando hai bisogno di selezionare pi\u00f9 propriet\u00e0 contemporaneamente. Qui \u00e8 dove il metodo JSONB si adatta veramente: semplicemente selezioniamo le propriet\u00e0 come colonne aggiuntive nel nostro set di risultati senza necessit\u00e0 di join:<\/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 avrai bisogno di 2 join per ogni propriet\u00e0 che desideri interrogare. A mio parere, le query sopra mostrano un grande semplificazione nel design del database. \u00c8 possibile vedere ulteriori esempi su come scrivere query in JSONB anche nel <noindex><a rel=\"nofollow\" href=\"http:\/\/schinckel.net\/2014\/05\/25\/querying-json-in-postgres\/\">seguente<\/a><\/noindex> post.<br \/>\nOra \u00e8 il momento di parlare delle prestazioni.<\/p>\n<h3>Prestazioni<\/h3>\n<p>\nPer confrontare le prestazioni, ho utilizzato <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/sql-explain.html\">EXPLAIN ANALYZE<\/a><\/noindex> nelle query, per misurare il tempo di esecuzione. Ogni query \u00e8 stata eseguita almeno tre volte, poich\u00e9 la prima volta il pianificatore delle query richiede pi\u00f9 tempo. Inizialmente ho eseguito le query senza alcun indice. Ovviamente, ci\u00f2 ha avvantaggiato JSONB, poich\u00e9 i join necessari per EAV non potevano utilizzare indici (i campi delle chiavi esterne non erano indicizzati). Dopo, ho creato un indice per due colonne delle chiavi esterne nella tabella dei valori EAV, oltre a un indice <noindex><a rel=\"nofollow\" href=\"http:\/\/www.postgresql.org\/docs\/9.1\/static\/textsearch-indexes.html\">GIN<\/a><\/noindex> per la colonna JSONB.<\/p>\n<p>Gli aggiornamenti dei dati hanno mostrato i seguenti risultati sui tempi (in ms). Si prega di notare che la scala \u00e8 logaritmica:<\/p>\n<p><img decoding=\"async\" alt=\"Sostituzione di EAV con JSONB in PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/8a12ccd7a46d04868b1cc5fcaf01a581.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSi osserva che JSONB \u00e8 molto pi\u00f9 (&gt; 50000 volte) veloce di EAV se non si utilizzano indici, a causa del motivo sopra indicato. Quando indicizziamo le colonne con le chiavi primarie, la differenza quasi scompare, ma JSONB \u00e8 ancora 1,3 volte pi\u00f9 veloce di EAV. Si noti che l'indice nella colonna JSONB qui non ha alcun impatto, poich\u00e9 non utilizziamo la colonna delle propriet\u00e0 nei criteri di valutazione. <\/p>\n<p>Per la selezione dei dati in base al valore della propriet\u00e0 otteniamo i seguenti risultati (scala normale):<\/p>\n<p><img decoding=\"async\" alt=\"Sostituzione di EAV con JSONB in PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/e9a1fd797ef60132e661da686f6214a3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSi pu\u00f2 notare che JSONB funziona di nuovo pi\u00f9 velocemente di EAV senza indici, ma quando EAV ha indici \u2013 comunque risulta pi\u00f9 veloce di JSONB. Tuttavia, ho notato che il tempo per le query JSONB era lo stesso, il che mi ha portato a pensare che l'indice GIN non si attivasse. Presumibilmente, quando si utilizza un indice GIN per una colonna con propriet\u00e0 popolate, questo funziona solo quando si usa l'operatore di inclusione @&gt;. Ho utilizzato questo in un nuovo test, il che ha avuto un enorme impatto sul tempo: solo 0,153 ms! Questo \u00e8 15000 volte pi\u00f9 veloce di EAV e 25000 volte pi\u00f9 veloce dell'operatore -&gt;&gt;. <\/p>\n<p>Penso che sia stato abbastanza veloce!<\/p>\n<h3>Dimensione delle tabelle del database<\/h3>\n<p>\nConfrontiamo le dimensioni delle tabelle con entrambi gli approcci. In psql possiamo mostrari la dimensione di tutte le tabelle e degli indici con il comando <b>dti+<\/b><\/p>\n<p><img decoding=\"async\" alt=\"Sostituzione di EAV con JSONB in PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/11\/c6c1fe7901fe9ae2bd446cf4ae99b923.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPer l'approccio EAV, le dimensioni delle tabelle ammontano a circa 3068 MB, e gli indici fino a 3427 MB, il che in totale equivale a 6,43 GB. Utilizzando l'approccio con JSONB si utilizzano 1817 MB per la tabella e 318 MB per gli indici, per un totale di 2,08 GB. Risultando in tre volte di meno! Questo fatto mi ha sorpreso un po', poich\u00e9 memorizziamo i nomi delle propriet\u00e0 in ogni oggetto JSONB. <\/p>\n<p>Tuttavia, i numeri parlano chiaro: in EAV conserviamo 2 chiavi esterne intere per il valore dell'attributo, il che si traduce in 8 byte di dati aggiuntivi. Inoltre, in EAV tutti i valori delle propriet\u00e0 sono memorizzati come testo, mentre JSONB utilizza valori numerici e booleani dove possibile, risultando in una dimensione complessiva inferiore.<\/p>\n<h3>Conclusioni<\/h3>\n<p>\nIn generale, penso che conservare le propriet\u00e0 delle entit\u00e0 nel formato JSONB possa semplificare notevolmente la progettazione e la manutenzione del vostro database. Se eseguite molte query, tutto ci\u00f2 che \u00e8 memorizzato in una sola tabella con l'entit\u00e0 funzioner\u00e0 davvero in modo pi\u00f9 efficiente. Il fatto che ci\u00f2 semplifichi l'interazione tra i dati \u00e8 gi\u00e0 un vantaggio, ma anche il database risultante \u00e8 tre volte pi\u00f9 piccolo in dimensione.<\/p>\n<p>Inoltre, dai test svolti, si pu\u00f2 concludere che le perdite di performance sono molto trascurabili. In alcuni casi, JSONB funziona anche pi\u00f9 velocemente rispetto a EAV, il che lo rende ancora migliore. Tuttavia, questo test di riferimento ovviamente non copre tutti gli aspetti (ad esempio, entit\u00e0 con un numero molto elevato di propriet\u00e0, un significativo aumento delle propriet\u00e0 dei dati esistenti, ecc.), quindi, se avete suggerimenti su come migliorarlo, non esitate a lasciarli nei commenti!<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.1.1 - 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\/it\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\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\/it\/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\udd47Sostituzione di EAV con JSONB in PostgreSQL | ProHoster","description":"TL; DR: JSONB pu\u00f2 semplificare notevolmente lo sviluppo di uno schema di database senza compromettere le performance delle query. Introduzione Presentiamo un esempio classico, probabilmente uno dei pi\u00f9 antichi.","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/zamena-eav-na-jsonb-v-postgresql","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","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\/it\/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\/it\/wp-json\/wp\/v2\/posts\/52584","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=52584"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/52584\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=52584"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=52584"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=52584"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}