Compatibilidad con JSON nativo en MYSQL 5.7: ¿cuáles son las ventajas y desventajas del tipo de datos JSON en MYSQL?

113

En MySQL 5.7 se ha agregado un nuevo tipo de datos para almacenar datos JSON en tablas MySQL . Obviamente, será un gran cambio en MySQL. Enumeraron algunos beneficios

Validación de documentos : solo se pueden almacenar documentos JSON válidos en una columna JSON, por lo que obtiene la validación automática de sus datos.

Acceso eficiente : lo que es más importante, cuando almacena un documento JSON en una columna JSON, no se almacena como un valor de texto sin formato. En cambio, se almacena en un formato binario optimizado que permite un acceso más rápido a los miembros del objeto y los elementos de la matriz.

Rendimiento : mejore el rendimiento de su consulta creando índices sobre valores dentro de las columnas JSON. Esto se puede lograr con "índices funcionales" en columnas virtuales.

Conveniencia : la sintaxis en línea adicional para columnas JSON hace que sea muy natural integrar las consultas de documentos en su SQL. Por ejemplo (features.feature es una columna JSON):SELECT feature->"$.properties.STREET" AS property_street FROM features WHERE id = 121254;

GUAUU ! incluyen algunas características excelentes. Ahora es más fácil manipular los datos. Ahora es posible almacenar datos más complejos en columna. Entonces MySQL ahora tiene sabor a NoSQL.

Ahora puedo imaginar una consulta para datos JSON algo como

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 );

Entonces, ¿puedo almacenar grandes relaciones pequeñas en pocas columnas json? ¿Esta bien? ¿Rompe la normalización? Si esto es posible, supongo que actuará como NoSQL en una columna MySQL . Realmente quiero saber más sobre esta función. Pros y contras del tipo de datos MySQL JSON.

Imran
fuente
oh, por favor, no digas lo que creo que estás diciendo. Toma, lee esto . La tuya es otra variante más de una mala idea.
Dibujó el
@Drew Has dado una gran respuesta. Pero no es mi pregunta. Solo quiero saber que si escribimos una consulta para datos json, entonces podemos omitir las reglas de SQL. porque no necesitamos muchas mesas
Imran
1
dijiste Now it is possible to store more complex data in column. Tenga cuidado
Drew
2
Índice de soporte de tipo de datos Json y tiene un tamaño inteligente: 64K y 4G. Entonces, ¿cuál es el problema si quiero almacenar 2000 datos y agregar 5 etiquetas anidadas en lugar de 5 tablas con relación?
Imran
5
"Realmente quiero saber más sobre esta función". y "Pros y contras del tipo de datos JSON de MySQL". no son preguntas y si se reformulan como preguntas son demasiado amplias. "Así que nunca pienso en una estructura de esquema compleja y claves externas en MySQL. Almaceno relaciones complejas usando solo unas pocas tablas". es autocontradictorio ya que JSON no es relaciones y FK. Una explicación de "es así de bueno" es solo una introducción al modelo relacional, así que nuevamente esto es demasiado amplio. Analice algunos ejemplos, haga su propia lista de pros y contras con referencias y pregunte en qué se equivocó.
philipxy

Respuestas:

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

El uso de una columna dentro de una expresión o función como esta arruina cualquier posibilidad de que la consulta utilice un índice para ayudar a optimizar la consulta. La consulta que se muestra arriba se ve obligada a realizar un escaneo de tabla.

La afirmación sobre el "acceso eficiente" es engañosa. Significa que después de que la consulta examina una fila con un documento JSON, puede extraer un campo sin tener que analizar el texto de la sintaxis JSON. Pero todavía se necesita un escaneo de tabla para buscar filas. En otras palabras, la consulta debe examinar cada fila.

Por analogía, si estoy buscando en una guía telefónica personas con el nombre de pila "Bill", todavía tengo que leer todas las páginas de la guía telefónica, incluso si los nombres se han resaltado para que sea un poco más rápido detectarlos.

MySQL 5.7 le permite definir una columna virtual en la tabla y luego crear un índice en la columna virtual.

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

Luego, si consulta la columna virtual, puede usar el índice y evitar el escaneo de la tabla.

SELECT * FROM t1
WHERE series IN ...

Esto es bueno, pero pierde el sentido de usar JSON. La parte atractiva de usar JSON es que le permite agregar nuevos atributos sin tener que hacer ALTER TABLE. Pero resulta que tienes que definir una columna adicional (virtual) de todos modos, si quieres buscar campos JSON con la ayuda de un índice.

Pero no tiene que definir índices y columnas virtuales para cada campo en el documento JSON, solo aquellos en los que desea buscar u ordenar. Podría haber otros atributos en el JSON que solo necesita extraer en la lista de selección como el siguiente:

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

En general, diría que esta es la mejor manera de usar JSON en MySQL. Solo en la lista de selección.

Cuando hace referencia a columnas en otras cláusulas (JOIN, WHERE, GROUP BY, HAVING, ORDER BY), es más eficiente usar columnas convencionales, no campos dentro de documentos JSON.

Presenté una charla titulada Cómo usar JSON en MySQL incorrectamente en la conferencia Percona Live en abril de 2018. Actualizaré y repetiré la charla en Oracle Code One en el otoño.

Hay otros problemas con JSON. Por ejemplo, en mis pruebas requirió de 2 a 3 veces más espacio de almacenamiento para documentos JSON en comparación con las columnas convencionales que almacenan los mismos datos.

MySQL está promocionando agresivamente sus nuevas capacidades JSON, en gran parte para disuadir a las personas de que no migren a MongoDB. Pero el almacenamiento de datos orientado a documentos como MongoDB es fundamentalmente una forma no relacional de organizar datos. Es diferente a relacional. No digo que una sea mejor que la otra, es solo una técnica diferente, adecuada para diferentes tipos de consultas.

Debe optar por usar JSON cuando JSON hace que sus consultas sean más eficientes.

No elija una tecnología solo porque es nueva o por el bien de la moda.


Editar: Se supone que la implementación de la columna virtual en MySQL usa el índice si su cláusula WHERE usa exactamente la misma expresión que la definición de la columna virtual. Es decir, lo siguiente debe usar el índice en la columna virtual, ya que la columna virtual está definidaAS (JSON_EXTRACT(data,"$.series"))

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

Excepto que, al probar esta función, descubrí que NO funciona por alguna razón si la expresión es una función de extracción JSON. Funciona para otros tipos de expresiones, pero no para funciones JSON.

Bill Karwin
fuente
7
Vale la pena seguir el enlace a las diapositivas
Paul Campbell
Buen punto las 2 tecnologías son buenas por sí mismas, decidimos cuál se ajustará a nuestras necesidades y cuál nos da más ventaja en términos de seguridad y rendimiento.
Christopher Pelayo
1
El quid del problema es que ALTER TABLE todavía es necesario para hacer uso de un índice en una columna generada para cada nueva clave en el JSON. Me alegro de que se señale.
user1454926
Solo si necesita agregar una columna virtual y / o un índice. Si trata los datos JSON como una "caja negra" y no intenta realizar consultas que busquen u ordenen subcampos dentro de JSON, no es necesario que lo haga. Es por eso que recomiendo para evitar hacer referencia a JSON en JOIN, WHEREu otras cláusulas. Simplemente busque la columna JSON en la lista de selección.
Bill Karwin
El enlace a las diapositivas está roto, @BillKarwin.
lagos son el
43

Lo siguiente de MySQL 5.7 trae de vuelta lo sexy con JSON me suena bien:

El uso del tipo de datos JSON en MySQL tiene dos ventajas sobre el almacenamiento de cadenas JSON en un campo de texto:

Validación de datos. Los documentos JSON se validarán automáticamente y los documentos no válidos producirán un error. Formato de almacenamiento interno mejorado. Los datos JSON se convierten a un formato que permite un acceso de lectura rápido a los datos en un formato estructurado. El servidor puede buscar subobjetos o valores anidados por clave o índice, lo que permite una mayor flexibilidad y rendimiento.

...

Los tipos especializados de tiendas NoSQL (bases de datos de documentos, tiendas de valores clave y bases de datos de gráficos) son probablemente mejores opciones para sus casos de uso específicos, pero la adición de este tipo de datos podría permitirle reducir la complejidad de su pila de tecnología. El precio es el acoplamiento a bases de datos MySQL (o compatibles). Pero eso no es un problema para muchos usuarios.

Tenga en cuenta el lenguaje sobre la validación de documentos, ya que es un factor importante. Supongo que es necesario realizar una serie de pruebas para comparar los dos enfoques. Esos dos son:

  1. Mysql con tipos de datos JSON
  2. Mysql sin

La red tiene slideshares poco profundos a partir de ahora sobre el tema de mysql / json / performance por lo que estoy viendo.

Quizás tu publicación pueda ser un centro para ello. O tal vez el rendimiento es un pensamiento posterior, no estoy seguro, y simplemente está emocionado de no crear un montón de tablas.

Dibujó
fuente
7
Una estafa; El tipo de datos JSON no es compatible con las tablas de memoria Mysql, como los tipos de datos, TEXT y BLOB. Esto significa que si se requiere una tabla temporal, se creará una tabla basada en disco, no en memoria. Algunos casos cuando una tabla temporal se utiliza aquí esbozados: dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html
medios Raiz
1
@raizmedia ¿Podría explicar por qué una tabla basada en disco es un problema frente a la memoria (tabla basada, supongo)?
lapin
@lapin Probablemente debido a limitaciones de velocidad.
Little Helper
@LittleHelper, puede evitarlo si usa una ranura PCI 4x 40 Gb / s M.2 e inserta una unidad compatible con 40 Gb / s. Esto funciona tan rápido como la memoria. También puede aplicar un formato especial a esa unidad que se utiliza para formatear la memoria.
Sergey Romanov
@SergeyRomanov, [citation required]¿ha comparado esa unidad con la RAM?
Bill Karwin
11

Me metí en este problema recientemente y resumo las siguientes experiencias:

1. No hay forma de resolver todas las preguntas. 2, debes usar el JSON correctamente.

Un caso:

Tengo una tabla llamada:, CustomFieldy debe tener dos columnas: name, fields. namees una cadena localizada, su contenido debería gustar:

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

Y fieldsdebería ser así:

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

Como puede ver, tanto el namecomo el fieldsse pueden guardar como JSON, ¡y funciona!

Sin embargo, si utilizo el namepara buscar en esta tabla con mucha frecuencia, ¿qué debo hacer? Utilice el JSON_CONTAINS, JSON_EXTRACT...? Obviamente, no es una idea buena para guardarlo como JSON más, debemos guardarlo en una tabla independiente: CustomFieldName.

Del caso anterior, creo que debes tener en cuenta estas ideas:

  1. ¿Por qué MYSQL es compatible con JSON?
  2. ¿Por qué quieres usar JSON? ¿Su lógica empresarial solo necesitaba esto? ¿O hay algo más?
  3. Nunca seas perezoso

Gracias

Bruce
fuente
2
Puede que le interese utilizar una columna VIRTUAL. percona.com/blog/2016/03/07/…
Bell
10

Desde mi experiencia, la implementación de JSON al menos en MySql 5.7 no es muy útil debido a su bajo rendimiento. Bueno, no es tan malo para la lectura de datos y la validación. Sin embargo, la modificación de JSON es de 10 a 20 veces más lenta con MySql que con Python o PHP. Imaginemos JSON muy simple:

{ "name": "value" }

Supongamos que tenemos que convertirlo en algo así:

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

Puede crear un script simple con Python o PHP que seleccionará todas las filas y las actualizará una por una. No está obligado a realizar una gran transacción para ello, por lo que otras aplicaciones pueden utilizar la tabla en paralelo. Por supuesto, también puede realizar una gran transacción si lo desea, por lo que tendrá la garantía de que MySql realizará "todo o nada", pero otras aplicaciones probablemente no podrán utilizar la base de datos durante la ejecución de la transacción.

Tengo una tabla de 40 millones de filas y la secuencia de comandos de Python la actualiza en 3-4 horas.

Ahora tenemos MySql JSON, por lo que ya no necesitamos Python o PHP, podemos hacer algo como eso:

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

Parece simple y excelente. Sin embargo, su velocidad es de 10 a 20 veces más lenta que la versión de Python, y es una transacción única, por lo que otras aplicaciones no pueden modificar los datos de la tabla en paralelo.

Por lo tanto, si solo queremos duplicar la clave JSON en una tabla de 40 millones de filas, no necesitamos usar la tabla en absoluto durante 30-40 horas. No tiene sentido.

Acerca de la lectura de datos, desde mi experiencia, el acceso directo al campo JSON a través de JSON_EXTRACTin WHEREtambién es extremadamente lento (mucho más lento que TEXTconLIKE una columna no indexada). Las columnas generadas virtuales funcionan mucho más rápido, sin embargo, si conocemos nuestra estructura de datos de antemano, no necesitamos JSON, podemos usar columnas tradicionales en su lugar. Cuando usamos JSON donde es realmente útil, es decir, cuando la estructura de datos es desconocida o cambia con frecuencia (por ejemplo, la configuración de complementos personalizados), la creación de columnas virtuales de forma regular para cualquier posible nueva columna no parece una buena idea.

Python y PHP hacen que la validación de JSON sea un encanto, por lo que es cuestionable si necesitamos la validación de JSON en el lado de MySql. ¿Por qué no también validar XML, documentos de Microsoft Office o revisar la ortografía? ;)

Vitalii
fuente