Cos'è JSON?
JSON sta per "JavaScript Object Notation" che è un tipo di formato di dati comunemente utilizzato dalle applicazioni web. Ciò significa che i dati verrebbero trasmessi tra applicazioni Web e server in tale formato. JSON è stato introdotto come alternativa al formato XML. Nei "bei vecchi tempi" i dati venivano trasmessi in formato XML, che è un tipo di dati pesante rispetto a JSON. Di seguito è riportato un esempio di stringa formattata JSON:
{ "ID":"001","name": "Ven", "Country": "Australia", "city": "Sydney", "Job Title":"Database Consultant"}
Una stringa JSON può contenere un altro oggetto JSON al suo interno come mostrato di seguito:
{ "ID":"001", "name": "Ven", "Job Title":"Database Consultant", "Location":{"Suburb":"Dee Why","city": "Sydney","State":"NSW","Country": "Australia"}}
Le moderne applicazioni Web e mobili generano principalmente i dati in formato JSON, chiamato anche "Byte JSON", che vengono prelevati dai server delle applicazioni e inviati al database. I byte JSON vengono a loro volta elaborati, suddivisi in valori di colonna separati e inseriti in una tabella RDBMS.
Esempio:
{ "ID":"001","name": "Ven", "Country": "Australia", "city": "Sydney", "Job Title":"Database Consultant"}
Sopra i dati JSON vengono convertiti in un SQL come sotto..
Insert into test (id, name, country,city,job_title) values (001,'Ven','Australia','Sydney','Database Consultant');
Quando si tratta di archiviare ed elaborare i dati JSON, ci sono vari database NoSQL che lo supportano e il più popolare è MongoDB. Quando si tratta di database RDBMS, fino a tempi recenti, le stringhe JSON venivano trattate come testo normale e non esistevano tipi di dati che riconoscessero, archiviassero o elaborassero specificamente le stringhe di formato JSON. PostgreSQL, il database RDBMS open source più popolare, ha creato un tipo di dati JSON che si è rivelato estremamente vantaggioso per le prestazioni, la funzionalità e la scalabilità quando si tratta di gestire i dati JSON.
PostgreSQL + JSON
Il database PostgreSQL è diventato sempre più popolare da quando è stato introdotto il tipo di dati JSON. In effetti, PostgreSQL ha superato MongoDB quando si tratta di elaborare una grande quantità di dati JSON. Le applicazioni possono memorizzare stringhe JSON nel database PostgreSQL nel formato JSON standard. Gli sviluppatori devono solo indicare all'applicazione di inviare le stringhe JSON al database come tipo di dati json e di recuperarle nel formato JSON. L'archiviazione della stringa JSON nel tipo di dati JSON presenta diversi vantaggi rispetto all'archiviazione della stessa nel tipo di dati TEXT. Il tipo di dati JSON può accettare solo stringhe formattate JSON valide, se la stringa non è nel formato JSON corretto, viene generato un errore. Il tipo di dati JSON aiuta l'applicazione a eseguire ricerche efficienti e basate sull'indice che vedremo in dettaglio a breve.
Il tipo di dati JSON è stato introdotto in PostgreSQL-9.2 dopo il quale sono stati apportati miglioramenti significativi. L'aggiunta principale è arrivata in PostgreSQL-9.4 con l'aggiunta del tipo di dati JSONB. JSONB è una versione avanzata del tipo di dati JSON che archivia i dati JSON in formato binario. Questo è il principale miglioramento che ha fatto una grande differenza nel modo in cui i dati JSON sono stati ricercati ed elaborati in PostgreSQL. Diamo uno sguardo dettagliato ai vantaggi dei tipi di dati JSON.
Tipi di dati JSON e JSONB
Il tipo di dati JSON memorizza le stringhe formattate json come testo che non è molto potente e non supporta molte funzioni relative a JSON utilizzate per le ricerche. Supporta solo l'indicizzazione B-TREE tradizionale e non supporta altri tipi di indici che sono indispensabili per operazioni di ricerca più rapide ed efficienti tra i dati JSON.
JSONB, la versione avanzata del tipo di dati JSON, è altamente raccomandato per l'archiviazione e l'elaborazione di documenti JSON. Supporta un'ampia gamma di operatori json e presenta numerosi vantaggi rispetto a JSON, come l'archiviazione di stringhe formattate JSON in formato binario e il supporto di funzioni e indicizzazione JSON per eseguire ricerche efficienti.
Vediamo le differenze.
JSON | JSONB | |
---|---|---|
1 | Più o meno come un tipo di dati TEXT che memorizza solo documenti JSON validi. | Memorizza i documenti JSON in formato binario. |
2 | Memorizza i documenti JSON così come sono, inclusi gli spazi bianchi. | Ritaglia gli spazi bianchi e li archivia in un formato favorevole a ricerche più rapide ed efficienti |
3 | Non supporta l'indicizzazione FULL-TEXT-SEARCH | Supporta l'indicizzazione FULL-TEXT-SEARCH |
4 | Non supporta un'ampia gamma di funzioni e operatori JSON | Supporta tutte le funzioni e gli operatori JSON |
Esempio per il numero 4 sopra elencato
JSON
Di seguito è riportata una tabella con tipo di dati JSON
dbt3=# \d product
Table "dbt3.product"
Column | Type | Collation | Nullable | Default
----------------+--------+-----------+----------+---------
item_code | bigint | | not null |
productdetails | json | | |
Indexes:
"product_pkey" PRIMARY KEY, btree (item_code)
Non supporta gli operatori JSON tradizionali (come "@>" o "#>"). La ricerca full-text tramite i dati JSON viene eseguita utilizzando "@>" o "#>" in un SQL che non è supportato dal tipo di dati JSON
dbt3=# select * from product where productdetails @> '{"l_shipmode":"AIR"}' and productdetails @> '{"l_quantity":"27"}';
ERROR: operator does not exist: json @> unknown
LINE 1: select * from product where productdetails @> '{"l_shipmode"...
^
HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
dbt3=#
JSONB
Di seguito è riportata una tabella con tipo di dati JSONB
dbt3=# \d products
Table "dbt3.products"
Column | Type | Collation | Nullable | Default
---------------+--------+-----------+----------+---------
item_code | bigint | | not null |
order_details | jsonb | | |
Indexes:
"products_pkey" PRIMARY KEY, btree (item_code)
Supporta FULL-TEXT-SEARCHING tramite dati JSON utilizzando operatori (come "@>")
dbt3=# select * from products where order_details @> '{"l_shipmode" : "AIR"}' limit 2;
item_code | order_details
-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4 | {"l_partkey": 21315, "l_orderkey": 1, "l_quantity": 28, "l_shipdate": "1996-04-21", "l_shipmode": "AIR", "l_commitdate": "1996-03-30", "l_shipinstruct": "NONE", "l_extendedprice": 34616.7}
8 | {"l_partkey": 42970, "l_orderkey": 3, "l_quantity": 45, "l_shipdate": "1994-02-02", "l_shipmode": "AIR", "l_commitdate": "1994-01-04", "l_shipinstruct": "NONE", "l_extendedprice": 86083.6}
(2 rows)
Scarica il whitepaper oggi Gestione e automazione di PostgreSQL con ClusterControlScopri cosa devi sapere per distribuire, monitorare, gestire e ridimensionare PostgreSQLScarica il whitepaper Come eseguire query sui dati JSON
Diamo un'occhiata ad alcune funzionalità JSON di PostgreSQL relative alle operazioni sui dati Di seguito è riportato l'aspetto dei dati JSON in una tabella. La colonna "order_details" è di tipo JSONB
dbt3=# select * from product_details ;
item_code | order_details
-----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 | {"l_partkey": 1551894, "l_orderkey": 1, "l_quantity": 17, "l_shipdate": "1996-03-13", "l_shipmode": "TRUCK", "l_commitdate": "1996-02-12", "l_shipinstruct": "DELIVER IN PERSON", "l_extendedprice": 33078.9}
2 | {"l_partkey": 673091, "l_orderkey": 1, "l_quantity": 36, "l_shipdate": "1996-04-12", "l_shipmode": "MAIL", "l_commitdate": "1996-02-28", "l_shipinstruct": "TAKE BACK RETURN", "l_extendedprice": 38306.2}
3 | {"l_partkey": 636998, "l_orderkey": 1, "l_quantity": 8, "l_shipdate": "1996-01-29", "l_shipmode": "REG AIR", "l_commitdate": "1996-03-05", "l_shipinstruct": "TAKE BACK RETURN", "l_extendedprice": 15479.7}
4 | {"l_partkey": 21315, "l_orderkey": 1, "l_quantity": 28, "l_shipdate": "1996-04-21", "l_shipmode": "AIR", "l_commitdate": "1996-03-30", "l_shipinstruct": "NONE", "l_extendedprice": 34616.7}
5 | {"l_partkey": 240267, "l_orderkey": 1, "l_quantity": 24, "l_shipdate": "1996-03-30", "l_shipmode": "FOB", "l_commitdate": "1996-03-14", "l_shipinstruct": "NONE", "l_extendedprice": 28974}
6 | {"l_partkey": 156345, "l_orderkey": 1, "l_quantity": 32, "l_shipdate": "1996-01-30", "l_shipmode": "MAIL", "l_commitdate": "1996-02-07", "l_shipinstruct": "DELIVER IN PERSON", "l_extendedprice": 44842.9}
7 | {"l_partkey": 1061698, "l_orderkey": 2, "l_quantity": 38, "l_shipdate": "1997-01-28", "l_shipmode": "RAIL", "l_commitdate": "1997-01-14", "l_shipinstruct": "TAKE BACK RETURN", "l_extendedprice": 63066.3}
8 | {"l_partkey": 42970, "l_orderkey": 3, "l_quantity": 45, "l_shipdate": "1994-02-02", "l_shipmode": "AIR", "l_commitdate": "1994-01-04", "l_shipinstruct": "NONE", "l_extendedprice": 86083.6}
9 | {"l_partkey": 190355, "l_orderkey": 3, "l_quantity": 49, "l_shipdate": "1993-11-09", "l_shipmode": "RAIL", "l_commitdate": "1993-12-20", "l_shipinstruct": "TAKE BACK RETURN", "l_extendedprice": 70822.1}
10 | {"l_partkey": 1284483, "l_orderkey": 3, "l_quantity": 27, "l_shipdate": "1994-01-16", "l_shipmode": "SHIP", "l_commitdate": "1993-11-22", "l_shipinstruct": "DELIVER IN PERSON", "l_extendedprice": 39620.3}
(10 rows)
Seleziona tutti i codici articolo comprese le date di spedizione
dbt3=# select item_code, order_details->'l_shipdate' as shipment_date from product_details ;
item_code | shipment_date
-----------+---------------
1 | "1996-03-13"
2 | "1996-04-12"
3 | "1996-01-29"
4 | "1996-04-21"
5 | "1996-03-30"
6 | "1996-01-30"
7 | "1997-01-28"
8 | "1994-02-02"
9 | "1993-11-09"
10 | "1994-01-16"
(10 rows)
Ottieni item_code, quantità e prezzo di tutti gli ordini arrivati per via aerea
dbt3=# select item_code, order_details->'l_quantity' as quantity, order_details->'l_extendedprice' as price, order_details->'l_shipmode' as price from product_details where order_details->>'l_shipmode'='AIR';
item_code | quantity | price | price
-----------+----------+---------+-------
4 | 28 | 34616.7 | "AIR"
8 | 45 | 86083.6 | "AIR"
(2 rows)
Gli operatori JSON “->” e “->>” vengono utilizzati per selezioni e confronti nella query SQL. L'operatore "->" restituisce il campo dell'oggetto JSON come campo tra virgolette e l'operatore "->>" restituisce il campo dell'oggetto JSON come TESTO. I due SQL precedenti sono esempi di visualizzazione dei valori dei campi JSON così come sono. Di seguito è riportato l'esempio di estrazione del campo JSON nel modulo TESTO.
Di seguito è riportato un esempio di recupero del campo JSON nel modulo TESTO
dbt3=# select item_code, order_details->>'l_shipdate' as shipment_date from product_details ;
item_code | shipment_date
-----------+---------------
1 | 1996-03-13
2 | 1996-04-12
3 | 1996-01-29
4 | 1996-04-21
5 | 1996-03-30
6 | 1996-01-30
7 | 1997-01-28
8 | 1994-02-02
9 | 1993-11-09
10 | 1994-01-16
(10 rows)
C'è un altro operatore chiamato "#>" che viene utilizzato per interrogare la parte di dati di un elemento JSON che è a sua volta parte di una stringa JSON. Diamo un'occhiata a un esempio.
Di seguito sono riportati i dati nella tabella.
dbt3=# select * from test_json ;
id | details
-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
10000 | {"Job": "Database Consultant", "name": "Venkata", "Location": {"city": "Sydney", "State": "NSW", "Suburb": "Dee Why", "Country": "Australia"}}
20000 | {"Job": "Database Consultant", "name": "Smith", "Location": {"city": "Sydney", "State": "NSW", "Suburb": "Manly", "Country": "Australia"}}
30000 | {"Job": "Developer", "name": "John", "Location": {"city": "Sydney", "State": "NSW", "Suburb": "Brookvale", "Country": "Australia"}}
50000 | {"cars": {"Ford": [{"doors": 4, "model": "Taurus"}, {"doors": 4, "model": "Escort"}], "Nissan": [{"doors": 4, "model": "Sentra"}, {"doors": 4, "model": "Maxima"}, {"doors": 2, "model": "Skyline"}]}}
40000 | {"Job": "Architect", "name": "James", "Location": {"city": "Melbourne", "State": "NSW", "Suburb": "Trugnania", "Country": "Australia"}}
Voglio vedere tutti i dettagli con "Stato" "NSW" e "Stato" è la chiave dell'oggetto JSON che fa parte della chiave "Posizione". Di seguito è riportato come interrogare lo stesso.
dbt3=# select * from test_json where details #> '{Location,State}'='"NSW"';
id | details
-------+------------------------------------------------------------------------------------------------------------------------------------------------
10000 | {"Job": "Database Consultant", "name": "Venkata", "Location": {"city": "Sydney", "State": "NSW", "Suburb": "Dee Why", "Country": "Australia"}}
20000 | {"Job": "Database Consultant", "name": "Smith", "Location": {"city": "Sydney", "State": "NSW", "Suburb": "Manly", "Country": "Australia"}}
30000 | {"Job": "Developer", "name": "John", "Location": {"city": "Sydney", "State": "NSW", "Suburb": "Brookvale", "Country": "Australia"}}
30000 | {"Job": "Architect", "name": "James", "Location": {"city": "Melbourne", "State": "NSW", "Suburb": "Trugnania", "Country": "Australia"}}
(4 rows)
Le operazioni aritmetiche possono essere eseguite su dati JSON. Il cast del tipo è necessario poiché la parte dei dati della colonna JSON è TEXT.
dbt3=# select item_code, order_details->'l_quantity' as quantity, order_details->'l_extendedprice' as price, order_details->'l_shipmode' as price from product_details where (order_details->'l_quantity')::int > 10;
item_code | quantity | price | price
-----------+----------+---------+---------
1 | 17 | 33078.9 | "TRUCK"
2 | 36 | 38306.2 | "MAIL"
4 | 28 | 34616.7 | "AIR"
5 | 24 | 28974 | "FOB"
6 | 32 | 44842.9 | "MAIL"
7 | 38 | 63066.3 | "RAIL"
8 | 45 | 86083.6 | "AIR"
9 | 49 | 70822.1 | "RAIL"
10 | 27 | 39620.3 | "SHIP"
(9 rows)
Oltre a quanto sopra, le seguenti operazioni possono essere eseguite anche su JSON utilizzando SQL inclusi JOIN
- Ordinamento dei dati utilizzando la clausola ORDER BY
- Aggregazione mediante funzioni aggregate come SUM, AVG, MIN, MAX ecc.
- Raggruppa i dati utilizzando la clausola GROUP BY
Che ne pensi delle prestazioni?
I dati nelle colonne JSON saranno di natura testuale e in base alle dimensioni dei dati possono verificarsi problemi di prestazioni. Le ricerche attraverso i dati JSON possono richiedere tempo e potenza di calcolo con conseguente lentezza nelle risposte alle applicazioni. È fondamentale che i DBA si assicurino che gli SQL che colpiscono le colonne JSON rispondano abbastanza velocemente e producano buone prestazioni. Poiché l'estrazione dei dati viene eseguita tramite SQL, l'opzione che i DBA cercherebbero è la possibilità di indicizzazione e sì, i tipi di dati JSON supportano le opzioni di indicizzazione.
Diamo un'occhiata alle opzioni di indicizzazione che JSON ci offre.
Indicizzazione JSONB
Il tipo di dati JSONB supporta l'indicizzazione FULL-TEXT-SEARCH. Questa è la funzionalità più importante di JSONB che i DBA non vedono l'ora di utilizzare i tipi di dati JSONB. Un normale indice su una chiave di un oggetto JSON potrebbe non essere d'aiuto quando si utilizzano operatori specifici JSON nelle query di ricerca. Di seguito è riportata una query TEXT SEARCH che va per una FULL-TABLE-SCAN
dbt3=# explain select * from products where order_details @> '{"l_shipmode" : "AIR"}';
QUERY PLAN
--------------------------------------------------------------------
Seq Scan on products (cost=0.00..4205822.65 rows=59986 width=252)
Filter: (order_details @> '{"l_shipmode": "AIR"}'::jsonb)
(2 rows)
JSONB supporta il tipo di indice FULL-TEXT-SEARCH chiamato GIN che aiuta le query come sopra.
Ora, fammi creare un indice GIN e vedere se questo aiuta
dbt3=# create index od_gin_idx on products using gin(order_details jsonb_path_ops);
CREATE INDEX
Se puoi osservare di seguito, la query raccoglie l'indice GIN
dbt3=# explain select * from products where order_details @> '{"l_shipmode" : "AIR"}';
QUERY PLAN
-------------------------------------------------------------------------------
Bitmap Heap Scan on products (cost=576.89..215803.18 rows=59986 width=252)
Recheck Cond: (order_details @> '{"l_shipmode": "AIR"}'::jsonb)
-> Bitmap Index Scan on od_gin_idx (cost=0.00..561.90 rows=59986 width=0)
Index Cond: (order_details @> '{"l_shipmode": "AIR"}'::jsonb)
E un indice B-TREE invece di GIN NON aiuterebbe
dbt3=# create index idx on products((order_details->>'l_shipmode'));
CREATE INDEX
dbt3=# \d products
Table "dbt3.products"
Column | Type | Collation | Nullable | Default
---------------+--------+-----------+----------+---------
item_code | bigint | | not null |
order_details | jsonb | | |
Indexes:
"products_pkey" PRIMARY KEY, btree (item_code)
"idx" btree ((order_details ->> 'l_shipmode'::text))
Puoi vedere di seguito, la query preferisce FULL-TABLE-SCAN
dbt3=# explain select * from products where order_details @> '{"l_shipmode" : "AIR"}';
QUERY PLAN
--------------------------------------------------------------------
Seq Scan on products (cost=0.00..4205822.65 rows=59986 width=252)
Filter: (order_details @> '{"l_shipmode": "AIR"}'::jsonb)
Cos'è l'indice GIN?
GIN sta per Generalized Inverted Index. La capacità principale di GIN Index è di velocizzare le ricerche full-text. Quando si esegue la ricerca in base a chiavi o elementi specifici in un TESTO o in un documento, GIN Index è la strada da percorrere. L'indice GIN memorizza le coppie "Chiave" (o un elemento o un valore) e la "lista posizioni". L'elenco delle posizioni è l'ID riga della chiave. Ciò significa che, se la "Chiave" si trova in più punti del documento, GIN Index memorizza la chiave solo una volta insieme alla sua posizione di occorrenze che non solo mantiene le dimensioni compatte dell'indice GIN e aiuta anche ad accelerare le ricerche in un grande strada. Questo è il miglioramento di Postgres-9.4.
Sfide con GIN Index
A seconda della complessità dei dati, il mantenimento degli indici GIN può essere costoso. La creazione di indici GIN consuma tempo e risorse poiché l'indice deve cercare nell'intero documento per trovare le chiavi e i relativi ID riga. Può essere ancora più difficile se l'indice GIN è gonfio. Inoltre, la dimensione dell'indice GIN può essere molto grande in base alla dimensione e alla complessità dei dati.
Indicizzazione JSON
JSON non supporta la ricerca di testo e gli indici come GIN
dbt3=# create index pd_gin_idx on product using gin(productdetails jsonb_path_ops);
ERROR: operator class "jsonb_path_ops" does not accept data type json
L'indicizzazione normale come B-TREE è supportata sia da JSON che da JSONB
Sì, gli indici normali come B-TREE Index sono supportati da entrambi i tipi di dati JSON e JSONB e non sono favorevoli per le operazioni di ricerca di testo. Ogni chiave oggetto JSON può essere indicizzata individualmente, il che sarebbe davvero di aiuto SOLO quando la stessa chiave oggetto viene utilizzata nella clausola WHERE.
Fammi creare un indice B-TREE su JSONB e vedere come funziona
dbt3=# create index idx on products((order_details->>'l_shipmode'));
CREATE INDEX
dbt3=# \d products
Table "dbt3.products"
Column | Type | Collation | Nullable | Default
---------------+--------+-----------+----------+---------
item_code | bigint | | not null |
order_details | jsonb | | |
Indexes:
"products_pkey" PRIMARY KEY, btree (item_code)
"idx" btree ((order_details ->> 'l_shipmode'::text))
Abbiamo già appreso sopra che un indice B-TREE NON è utile per velocizzare gli SQL eseguendo FULL-TEXT-SEARCHING sui dati JSON utilizzando operatori (come "@>") e tali indici aiuterebbero SOLO ad accelerare le query come quello sotto, che sono tipici SQL di tipo RDBMS (che non sono query di ricerca). Ciascuna chiave dell'oggetto JSON può essere indicizzata individualmente, il che aiuterebbe a velocizzare le query quando tali chiavi dell'oggetto JSON indicizzate vengono utilizzate nella clausola WHERE.
L'esempio seguente la query utilizza la chiave dell'oggetto "l_shipmode" nella clausola WHERE e poiché è indicizzato la query sta per eseguire una scansione dell'indice. Se desideri eseguire la ricerca utilizzando una chiave oggetto diversa, la query sceglierà di eseguire una SCANSIONE COMPLETA DELLA TABELLA.
dbt3=# explain select * from products where order_details->>'l_shipmode'='AIR';
QUERY PLAN
---------------------------------------------------------------------------------
Index Scan using idx on products (cost=0.56..1158369.34 rows=299930 width=252)
Index Cond: ((order_details ->> 'l_shipmode'::text) = 'AIR'::text)
Lo stesso funziona anche con il tipo di dati JSON
dbt3=# create index idx on products((order_details->>'l_shipmode'));
CREATE INDEX
dbt3=# \d products
Table "dbt3.products"
Column | Type | Collation | Nullable | Default
---------------+--------+-----------+----------+---------
item_code | bigint | | not null |
order_details | json | | |
Indexes:
"products_pkey" PRIMARY KEY, btree (item_code)
"idx" btree ((order_details ->> 'l_shipmode'::text))
Se puoi osservare, la query utilizza l'Indice
dbt3=# explain select * from products where order_details->>'l_shipmode'='AIR';
QUERY PLAN
---------------------------------------------------------------------------------
Index Scan using idx on products (cost=0.56..1158369.34 rows=299930 width=252)
Index Cond: ((order_details ->> 'l_shipmode'::text) = 'AIR'::text)
Conclusione
Ecco alcune cose da ricordare quando si utilizza PostgreSQL JSON Data...
- PostgreSQL è una delle migliori opzioni per archiviare ed elaborare dati JSON
- Con tutte le potenti funzionalità, PostgreSQL può essere il tuo database di documenti
- Ho visto architetture in cui vengono scelti due o più archivi di dati, con una combinazione di database PostgreSQL e NoSQL come MongoDB o database Couchbase. Un'API REST aiuterebbe le applicazioni a inviare i dati a diversi archivi dati. Con PostgreSQL che supporta JSON, questa complessità nell'architettura può essere evitata semplicemente scegliendo un archivio dati.
- I dati JSON in PostgreSQL possono essere interrogati e indicizzati, il che rende incredibili prestazioni e scalabilità
- Il tipo di dati JSONB è l'opzione preferita in quanto è buono per l'archiviazione e le prestazioni. Supporta pienamente la RICERCA DI TESTO COMPLETO e l'indicizzazione. Offre buone prestazioni
- Utilizza il tipo di dati JSON solo se desideri archiviare stringhe JSON come JSON e non esegui ricerche di testo molto complesse
- Il più grande vantaggio di avere JSON in PostgreSQL è che la ricerca può essere eseguita utilizzando SQL
- Le prestazioni di ricerca JSON in PostgreSQL sono state alla pari con i migliori database NoSQL come MongoDB