Supporto JSON nativo in MYSQL 5.7: quali sono i pro e i contro del tipo di dati JSON in MYSQL?


113

In MySQL 5.7 è stato aggiunto un nuovo tipo di dati per l'archiviazione dei dati JSON nelle tabelle MySQL . Ovviamente sarà un grande cambiamento in MySQL. Hanno elencato alcuni vantaggi

Convalida dei documenti : solo i documenti JSON validi possono essere archiviati in una colonna JSON, in modo da ottenere la convalida automatica dei dati.

Accesso efficiente : ancora più importante, quando si archivia un documento JSON in una colonna JSON, non viene archiviato come valore di testo normale. Viene invece archiviato in un formato binario ottimizzato che consente un accesso più rapido ai membri degli oggetti e agli elementi dell'array.

Prestazioni : migliora le prestazioni delle query creando indici sui valori all'interno delle colonne JSON. Ciò può essere ottenuto con "indici funzionali" su colonne virtuali.

Praticità : la sintassi inline aggiuntiva per le colonne JSON rende molto naturale integrare le query del documento all'interno del tuo SQL. Ad esempio (features.feature è una colonna JSON):SELECT feature->"$.properties.STREET" AS property_street FROM features WHERE id = 121254;

WOW ! includono alcune fantastiche funzionalità. Ora è più facile manipolare i dati. Ora è possibile memorizzare dati più complessi in colonna. Quindi MySQL è ora aromatizzato con NoSQL.

Ora posso immaginare una query per i dati JSON qualcosa di simile

SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN 
( 
SELECT JSON_EXTRACT(data,"$.inverted") 
FROM t1 | {"series": 3, "inverted": 8} 
WHERE JSON_EXTRACT(data,"$.inverted")<4 );

Quindi posso memorizzare piccole relazioni enormi in poche colonne json? È buono? Infrange la normalizzazione. Se questo è possibile, immagino che agirà come NoSQL in una colonna MySQL . Voglio davvero saperne di più su questa funzione. Pro e contro del tipo di dati JSON di MySQL.


oh, per favore, non dire quello che penso tu stia dicendo. Ecco, leggi questo . La tua è un'altra variante di una cattiva idea.
Drew

@Drew Hai dato una grande risposta. Ma non è la mia domanda. Voglio solo sapere che se scriviamo una query per i dati json, potremmo saltare le regole sql. perché non abbiamo bisogno di molti tavoli
Imran

1
hai detto Now it is possible to store more complex data in column. Fai attenzione
Drew

2
Indice di supporto del tipo di dati Json e dimensioni intelligenti: 64K e 4G. Quindi qual è il problema se voglio memorizzare 2000 dati e aggiungere 5 etichette nidificate invece di 5 tabelle con relazione?
Imran

5
"Voglio davvero saperne di più su questa funzione." e "Pro e contro del tipo di dati JSON di MySQL". non sono domande, e se riformulate come domande sono troppo ampie. "Quindi non penso mai a una struttura di schema complessa e chiavi esterne in MySQL. Memorizzo relazioni complesse utilizzando solo poche tabelle." è contraddittorio poiché JSON non è relazioni e FK. Una spiegazione di "è così buono" è solo un'introduzione al modello relazionale, quindi anche questo è troppo ampio. Analizza alcuni esempi, crea il tuo elenco di pro e contro con i riferimenti e chiedi dove hai sbagliato.
philipxy

Risposte:


57
SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN ...

L'uso di una colonna all'interno di un'espressione o di una funzione come questa rovina ogni possibilità che la query utilizzi un indice per ottimizzare la query. La query mostrata sopra è costretta a eseguire una scansione della tabella.

L'affermazione di "accesso efficiente" è fuorviante. Significa che dopo che la query ha esaminato una riga con un documento JSON, può estrarre un campo senza dover analizzare il testo della sintassi JSON. Ma è comunque necessaria una scansione della tabella per cercare le righe. In altre parole, la query deve esaminare ogni riga.

Per analogia, se cerco in un elenco telefonico persone con il nome "Bill", devo comunque leggere ogni pagina dell'elenco telefonico, anche se i primi nomi sono stati evidenziati per renderli leggermente più rapidi.

MySQL 5.7 consente di definire una colonna virtuale nella tabella e quindi creare un indice sulla colonna virtuale.

ALTER TABLE t1
  ADD COLUMN series AS (JSON_EXTRACT(data, '$.series')),
  ADD INDEX (series);

Quindi, se interroghi la colonna virtuale, può usare l'indice ed evitare la scansione della tabella.

SELECT * FROM t1
WHERE series IN ...

Questo è carino, ma in un certo senso non ha senso usare JSON. La parte interessante dell'utilizzo di JSON è che ti consente di aggiungere nuovi attributi senza dover fare ALTER TABLE. Ma risulta che devi comunque definire una colonna extra (virtuale), se vuoi cercare nei campi JSON con l'aiuto di un indice.

Ma non è necessario definire colonne e indici virtuali per ogni campo nel documento JSON, solo quelli in cui si desidera cercare o ordinare. Potrebbero esserci altri attributi nel JSON che devi solo estrarre nell'elenco di selezione come il seguente:

SELECT JSON_EXTRACT(data, '$.series') AS series FROM t1
WHERE <other conditions>

In genere direi che questo è il modo migliore per utilizzare JSON in MySQL. Solo nell'elenco di selezione.

Quando si fa riferimento a colonne in altre clausole (JOIN, WHERE, GROUP BY, HAVING, ORDER BY), è più efficiente utilizzare colonne convenzionali, non campi all'interno di documenti JSON.

Ho presentato un discorso intitolato Come usare JSON in MySQL Wrong alla conferenza Percona Live nell'aprile 2018. Aggiornerò e ripeterò il discorso a Oracle Code One in autunno.

Ci sono altri problemi con JSON. Ad esempio, nei miei test ha richiesto 2-3 volte più spazio di archiviazione per i documenti JSON rispetto alle colonne convenzionali che memorizzano gli stessi dati.

MySQL sta promuovendo le nuove funzionalità JSON in modo aggressivo, in gran parte per dissuadere le persone dal migrare a MongoDB. Ma l'archiviazione dei dati orientata ai documenti come MongoDB è fondamentalmente un modo non relazionale di organizzare i dati. È diverso dal relazionale. Non sto dicendo che uno sia migliore dell'altro, è solo una tecnica diversa, adatta a diversi tipi di query.

Dovresti scegliere di utilizzare JSON quando JSON rende le tue query più efficienti.

Non scegliere una tecnologia solo perché è nuova o per il gusto della moda.


Modifica: l'implementazione della colonna virtuale in MySQL dovrebbe utilizzare l'indice se la clausola WHERE utilizza esattamente la stessa espressione della definizione della colonna virtuale. Ovvero, quanto segue dovrebbe utilizzare l'indice sulla colonna virtuale, poiché la colonna virtuale è definitaAS (JSON_EXTRACT(data,"$.series"))

SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN ...

Tranne che ho scoperto testando questa funzione che NON funziona per qualche motivo se l'espressione è una funzione di estrazione JSON. Funziona per altri tipi di espressioni, non solo per le funzioni JSON.


7
Vale la pena seguire il link alle diapositive
Paul Campbell

Un aspetto positivo che le 2 tecnologie sono entrambe buone di per sé significa che decidiamo quale si adatta alle nostre esigenze e cosa ci dà più vantaggio in termini di sicurezza e prestazioni.
Christopher Pelayo

1
Il punto cruciale del problema è che ALTER TABLE è ancora necessario per utilizzare un indice su una colonna generata per ogni nuova chiave nel JSON. Sono contento di vederlo sottolineato.
user1454926

Solo se è necessario aggiungere una colonna virtuale e / o un indice. Se tratti i dati JSON come una "scatola nera" e non provi a eseguire query che cercano o ordinano i sottocampi all'interno di JSON, non è necessario farlo. Ecco perché vi consiglio di evitare riferimenti JSON in JOIN, WHEREo di altre clausole. Basta recuperare la colonna JSON nell'elenco di selezione.
Bill Karwin

Il collegamento alle diapositive è interrotto, @BillKarwin.
Lakesare

43

Quanto segue da MySQL 5.7 riporta sexy con JSON suona bene per me:

L'utilizzo del tipo di dati JSON in MySQL presenta due vantaggi rispetto all'archiviazione di stringhe JSON in un campo di testo:

Convalida dei dati. I documenti JSON verranno convalidati automaticamente e i documenti non validi produrranno un errore. Formato di archiviazione interno migliorato. I dati JSON vengono convertiti in un formato che consente un rapido accesso in lettura ai dati in un formato strutturato. Il server è in grado di cercare suboggetti o valori nidificati per chiave o indice, consentendo maggiore flessibilità e prestazioni.

...

Le versioni specializzate di archivi NoSQL (database di documenti, archivi di valori-chiave e DB di grafici) sono probabilmente opzioni migliori per i loro casi d'uso specifici, ma l'aggiunta di questo tipo di dati potrebbe consentire di ridurre la complessità dello stack tecnologico. Il prezzo è accoppiato a database MySQL (o compatibili). Ma questo non è un problema per molti utenti.

Nota il linguaggio sulla convalida dei documenti poiché è un fattore importante. Immagino che sia necessario eseguire una serie di test per confrontare i due approcci. Quei due sono:

  1. Mysql con tipi di dati JSON
  2. Mysql senza

La rete ha solo diapositive poco profonde fin d'ora sul tema di mysql / json / prestazioni da quello che sto vedendo.

Forse il tuo post può essere un hub per questo. O forse la performance è un ripensamento, non ne sono sicuro, e sei semplicemente entusiasta di non creare un mucchio di tavoli.


7
Una truffa; Il tipo di dati JSON non è supportato dalle tabelle Mysql Memory, come i tipi di dati, TEXT e BLOB. Ciò significa che se è richiesta una tabella temporanea, verrà creata una tabella basata su disco non memoria. Alcuni casi in cui viene utilizzata una tabella temporanea sono descritti qui: dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html
raiz media

1
@raizmedia Potresti spiegare il motivo per cui una tabella basata su disco è un problema rispetto alla memoria (una tabella basata immagino)?
lapin

@lapin Probabilmente a causa dei limiti di velocità.
Little Helper

@LittleHelper puoi evitarlo se usi uno slot PCI 4x 40 Gb / s M.2 e inserisci un'unità supportata da 40 Gb / s. Funziona velocemente come memmory. Puoi anche applicare un formato speciale a quell'unità che viene utilizzata per formattare memmory.
Sergey Romanov

@SergeyRomanov, [citation required]hai confrontato l'unità con la RAM?
Bill Karwin il

11

Mi sono imbattuto in questo problema di recente e riassumo le seguenti esperienze:

1, non c'è un modo per risolvere tutte le domande. 2, dovresti usare correttamente JSON.

Un caso:

Ho una tabella denominata:, CustomFielde deve contenere due colonne: name, fields. nameè una stringa localizzata, il suo contenuto dovrebbe essere simile a:

{
  "en":"this is English name",
  "zh":"this is Chinese name"
   ...(other languages)
}

E fieldsdovrebbe essere così:

[
  {
    "filed1":"value",
    "filed2":"value"
    ...
  },
  {
    "filed1":"value",
    "filed2":"value"
    ...
  }
  ...
]

Come puoi vedere, sia il nameche il fieldspossono essere salvati come JSON e funziona!

Tuttavia, se utilizzo namemolto spesso questa tabella, cosa devo fare? Usa il JSON_CONTAINS, JSON_EXTRACT...? Ovviamente, non è una buona idea per salvarlo come JSON più, dobbiamo salvarlo in una tabella indipendenti: CustomFieldName.

Dal caso precedente, penso che dovresti tenere a mente queste idee:

  1. Perché MYSQL supporta JSON?
  2. Perché vuoi usare JSON? La tua logica aziendale ne aveva bisogno? Oppure c'è qualcos'altro?
  3. Non essere mai pigro

Grazie


2
Potresti essere interessato a utilizzare una colonna VIRTUALE. percona.com/blog/2016/03/07/…
Bell

10

Dalla mia esperienza, l'implementazione di JSON almeno in MySql 5.7 non è molto utile a causa delle sue scarse prestazioni. Bene, non è così male per la lettura dei dati e la convalida. Tuttavia, la modifica JSON è 10-20 volte più lenta con MySql che con Python o PHP. Immaginiamo un JSON molto semplice:

{ "name": "value" }

Supponiamo di doverlo convertire in qualcosa del genere:

{ "name": "value", "newName": "value" }

Puoi creare un semplice script con Python o PHP che selezionerà tutte le righe e le aggiornerà una per una. Non sei obbligato a fare una transazione enorme per questo, quindi altre applicazioni potranno utilizzare la tabella in parallelo. Naturalmente, puoi anche fare una grande transazione se vuoi, così avrai la garanzia che MySql eseguirà "tutto o niente", ma molto probabilmente altre applicazioni non saranno in grado di utilizzare il database durante l'esecuzione della transazione.

Ho una tabella di 40 milioni di righe e lo script Python lo aggiorna in 3-4 ore.

Ora abbiamo MySql JSON, quindi non abbiamo più bisogno di Python o PHP, possiamo fare qualcosa del genere:

UPDATE `JsonTable` SET `JsonColumn` = JSON_SET(`JsonColumn`, "newName", JSON_EXTRACT(`JsonColumn`, "name"))

Sembra semplice ed eccellente. Tuttavia, la sua velocità è 10-20 volte più lenta della versione Python ed è a transazione singola, quindi altre applicazioni non possono modificare i dati della tabella in parallelo.

Quindi, se vogliamo semplicemente duplicare la chiave JSON in una tabella di 40 milioni di righe, non dobbiamo usare affatto la tabella per 30-40 ore. Non ha senso.

Per quanto riguarda la lettura dei dati, dalla mia esperienza l'accesso diretto al campo JSON tramite JSON_EXTRACTin WHEREè anche estremamente lento (molto più lento di quello TEXTcon una LIKEcolonna non indicizzata). Le colonne generate virtuali funzionano molto più velocemente, tuttavia, se conosciamo in anticipo la nostra struttura dati, non abbiamo bisogno di JSON, possiamo invece utilizzare colonne tradizionali. Quando usiamo JSON dove è veramente utile, cioè quando la struttura dei dati è sconosciuta o cambia spesso (ad esempio, le impostazioni del plug-in personalizzato), la creazione di colonne virtuali su base regolare per eventuali nuove colonne non sembra una buona idea.

Python e PHP rendono la convalida JSON come un fascino, quindi è discutibile se abbiamo bisogno della convalida JSON sul lato MySql. Perché non convalidare anche XML, documenti di Microsoft Office o controllare l'ortografia? ;)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.