Suporte nativo a JSON em MYSQL 5.7: quais são os prós e contras do tipo de dados JSON em MYSQL?

113

No MySQL 5.7, um novo tipo de dados para armazenar dados JSON em tabelas MySQL foi adicionado. Obviamente, será uma grande mudança no MySQL. Eles listaram alguns benefícios

Validação de documento - apenas documentos JSON válidos podem ser armazenados em uma coluna JSON, para que você obtenha validação automática de seus dados.

Acesso eficiente - mais importante, quando você armazena um documento JSON em uma coluna JSON, ele não é armazenado como um valor de texto simples. Em vez disso, ele é armazenado em um formato binário otimizado que permite acesso mais rápido aos membros do objeto e elementos da matriz.

Desempenho - melhore o desempenho de sua consulta criando índices em valores nas colunas JSON. Isso pode ser alcançado com “índices funcionais” em colunas virtuais.

Conveniência - A sintaxe inline adicional para colunas JSON torna muito natural integrar consultas de documentos em seu SQL. Por exemplo (features.feature é uma coluna JSON):SELECT feature->"$.properties.STREET" AS property_street FROM features WHERE id = 121254;

UAU ! eles incluem alguns recursos excelentes. Agora é mais fácil manipular dados. Agora é possível armazenar dados mais complexos na coluna. Portanto, o MySQL agora é temperado com NoSQL.

Agora posso imaginar uma consulta de dados 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 );

Então, posso armazenar pequenas relações enormes em poucos json colum? Isso é bom? Isso quebra a normalização. Se isso for possível, acho que funcionará como NoSQL em uma coluna MySQL . Eu realmente quero saber mais sobre esse recurso. Prós e contras do tipo de dados JSON do MySQL.

Imran
fonte
oh, por favor, não diga o que eu acho que você está dizendo. Aqui, leia isto . A sua é mais uma variante de uma má ideia.
Desenhou em
@Drew Você deu uma grande resposta. Mas não é minha pergunta. Só quero saber que, se escrevermos uma consulta para dados json, podemos pular as regras do sql. porque não precisamos de muitas mesas
Imran
1
você disse Now it is possible to store more complex data in column. Tenha cuidado
Drew
2
Índice de suporte de tipo de dados Json e tamanho inteligente: 64K e 4G. Então, qual é o problema se eu quiser armazenar dados de 2000 e adicionar 5 rótulos aninhados em vez de 5 tabelas com relação?
Imran
5
"Eu realmente quero saber mais sobre esse recurso." e "Prós e contras do tipo de dados JSON do MySQL". não são perguntas e, se reformuladas como perguntas, são muito amplas. "Portanto, nunca penso em uma estrutura de esquema complexa e chaves estrangeiras no MySQL. Armazeno relações complexas usando apenas algumas tabelas." é contraditório, uma vez que JSON não é relações e FKs. Uma explicação de "isso é bom" é apenas uma introdução ao modelo relacional, então, novamente, isso é muito amplo. Trabalhe com alguns exemplos, faça sua própria lista de prós e contras com referências e pergunte onde você errou.
philipxy

Respostas:

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

Usar uma coluna dentro de uma expressão ou função como essa estraga qualquer chance de a consulta usar um índice para ajudar a otimizar a consulta. A consulta mostrada acima é forçada a fazer uma varredura de tabela.

A afirmação sobre "acesso eficiente" é enganosa. Isso significa que, após a consulta examinar uma linha com um documento JSON, ela pode extrair um campo sem precisar analisar o texto da sintaxe JSON. Mas ainda é necessária uma varredura de tabela para pesquisar linhas. Em outras palavras, a consulta deve examinar todas as linhas.

Por analogia, se estou pesquisando uma lista telefônica por pessoas com o primeiro nome "Bill", ainda tenho que ler todas as páginas da lista telefônica, mesmo que os primeiros nomes tenham sido destacados para tornar um pouco mais rápido identificá-los.

O MySQL 5.7 permite que você defina uma coluna virtual na tabela e, em seguida, crie um índice na coluna virtual.

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

Então, se você consultar a coluna virtual, ela pode usar o índice e evitar a varredura da tabela.

SELECT * FROM t1
WHERE series IN ...

Isso é bom, mas meio que perde o sentido de usar JSON. A parte atrativa de usar JSON é que ele permite adicionar novos atributos sem ter que fazer ALTER TABLE. Mas acontece que você precisa definir uma coluna extra (virtual) de qualquer maneira, se quiser pesquisar campos JSON com a ajuda de um índice.

Mas você não precisa definir colunas e índices virtuais para cada campo no documento JSON - apenas aqueles que deseja pesquisar ou classificar. Pode haver outros atributos no JSON que você só precisa extrair na lista de seleção como o seguinte:

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

Eu geralmente diria que esta é a melhor maneira de usar JSON no MySQL. Apenas na lista de seleção.

Quando você faz referência a colunas em outras cláusulas (JOIN, WHERE, GROUP BY, HAVING, ORDER BY), é mais eficiente usar colunas convencionais, não campos em documentos JSON.

Apresentei uma palestra chamada How to Use JSON in MySQL Wrong na conferência Percona Live em abril de 2018. Atualizarei e repetirei a palestra no Oracle Code One no outono.

Existem outros problemas com JSON. Por exemplo, em meus testes, exigiu 2 a 3 vezes mais espaço de armazenamento para documentos JSON em comparação com colunas convencionais que armazenam os mesmos dados.

O MySQL está promovendo seus novos recursos JSON agressivamente, principalmente para dissuadir as pessoas contra a migração para o MongoDB. Mas o armazenamento de dados orientado a documentos, como o MongoDB, é fundamentalmente uma forma não relacional de organizar dados. É diferente de relacional. Não estou dizendo que um seja melhor do que o outro, é apenas uma técnica diferente, adequada para diferentes tipos de consultas.

Você deve escolher usar JSON quando JSON tornar suas consultas mais eficientes.

Não escolha uma tecnologia apenas porque é nova ou por uma questão de moda.


Editar: A implementação da coluna virtual no MySQL deve usar o índice se sua cláusula WHERE usar exatamente a mesma expressão que a definição da coluna virtual. Ou seja, o seguinte deve usar o índice na coluna virtual, uma vez que a coluna virtual está definidaAS (JSON_EXTRACT(data,"$.series"))

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

Exceto que eu descobri, testando este recurso, que ele NÃO funciona por algum motivo se a expressão for uma função de extração JSON. Ele funciona para outros tipos de expressões, mas não para funções JSON.

Bill Karwin
fonte
7
Vale a pena seguir o link para os slides
Paul Campbell
Bom ponto, as 2 tecnologias são boas em seus próprios meios, podemos decidir qual vai atender às nossas necessidades e o que nos dá mais vantagem em termos de segurança e desempenho.
Christopher Pelayo
1
O cerne do problema é que ALTER TABLE ainda é necessário para fazer uso de um índice em uma coluna gerada para cada nova chave no JSON. Fico feliz em ver isso sendo apontado.
user1454926
Somente se você precisar adicionar uma coluna virtual e / ou um índice. Se você tratar os dados JSON como uma "caixa preta" e não tentar fazer nenhuma consulta que pesquise ou classifique subcampos dentro do JSON, não será necessário fazer isso. É por isso que eu recomendo para evitar referência JSON em JOIN, WHEREou outras cláusulas. Basta buscar a coluna JSON na lista de seleção.
Bill Karwin de
O link para os slides está quebrado, @BillKarwin.
lagos são
43

O seguinte do MySQL 5.7 traz de volta a sensualidade com JSON parece bom para mim:

Usar o tipo de dados JSON no MySQL traz duas vantagens sobre o armazenamento de strings JSON em um campo de texto:

Data de validade. Documentos JSON serão validados automaticamente e documentos inválidos produzirão um erro. Formato de armazenamento interno aprimorado. Os dados JSON são convertidos em um formato que permite acesso de leitura rápida aos dados em um formato estruturado. O servidor é capaz de pesquisar subobjetos ou valores aninhados por chave ou índice, permitindo flexibilidade e desempenho adicionais.

...

Tipos especializados de armazenamentos NoSQL (bancos de dados de documentos, armazenamentos de valores-chave e bancos de dados gráficos) são provavelmente as melhores opções para seus casos de uso específicos, mas a adição deste tipo de dados pode permitir que você reduza a complexidade de sua pilha de tecnologia. O preço é acoplado a bancos de dados MySQL (ou compatíveis). Mas isso não é problema para muitos usuários.

Observe o idioma sobre a validação do documento , pois é um fator importante. Eu acho que uma bateria de testes precisa ser executada para comparações das duas abordagens. Esses dois sendo:

  1. Mysql com tipos de dados JSON
  2. Mysql sem

A rede tem slideshares superficiais a partir de agora sobre o tópico mysql / json / performance pelo que estou vendo.

Talvez sua postagem possa ser um centro para isso. Ou talvez o desempenho seja uma reflexão tardia, não tenho certeza, e você está apenas animado para não criar um monte de tabelas.

Desenhou
fonte
7
Um golpe; O tipo de dados JSON não é compatível com as tabelas de memória Mysql, como os tipos de dados, TEXTO e BLOB. Isso significa que se uma tabela temporária for necessária, será criada uma tabela baseada em disco, não em memória. Alguns casos em que uma tabela temporária é usada são descritos aqui: dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html
raiz media
1
@raizmedia Você poderia explicar por que uma tabela baseada em disco é um problema versus memória (tabela baseada eu acho)?
volta de
@lapin Provavelmente devido a limitações de velocidade.
Little Helper
@LittleHelper você pode evitá-lo se usar o slot PCI 4x 40 Gb / s M.2 e inserir uma unidade compatível de 40 Gb / s. Isso funciona tão rápido quanto a memória. Você também pode aplicar um formato especial àquela unidade que é usada para formatar a memória.
Sergey Romanov
@SergeyRomanov, [citation required]você comparou essa unidade com a RAM?
Bill Karwin
11

Tive esse problema recentemente e resumi as seguintes experiências:

1, Não há como resolver todas as questões. 2, você deve usar o JSON corretamente.

Um caso:

Eu tenho uma tabela chamada: CustomFielde deve ter duas colunas: name, fields. nameé uma string localizada, o conteúdo deve ser:

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

E fieldsdeve ser assim:

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

Como você pode ver, tanto o namequanto o fieldspodem ser salvos como JSON e funciona!

No entanto, se eu usar o namepara pesquisar esta tabela com muita frequência, o que devo fazer? Use o JSON_CONTAINS, JSON_EXTRACT...? Obviamente, não é uma boa idéia para salvá-lo como JSON mais, devemos guardá-lo para uma tabela independente: CustomFieldName.

Do caso acima, acho que você deve manter estas idéias em mente:

  1. Por que o MYSQL suporta JSON?
  2. Por que você deseja usar JSON? Sua lógica de negócios só precisava disso? Ou há outra coisa?
  3. Nunca seja preguiçoso

obrigado

Bruce
fonte
2
Você pode estar interessado em usar uma coluna VIRTUAL. percona.com/blog/2016/03/07/…
Bell
10

Pela minha experiência, a implementação JSON pelo menos no MySql 5.7 não é muito útil devido ao seu baixo desempenho. Bem, não é tão ruim para leitura de dados e validação. No entanto, a modificação JSON é 10-20 vezes mais lenta com MySql do que com Python ou PHP. Vamos imaginar um JSON muito simples:

{ "name": "value" }

Vamos supor que tenhamos que convertê-lo para algo assim:

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

Você pode criar um script simples com Python ou PHP que selecionará todas as linhas e as atualizará uma por uma. Você não é forçado a fazer uma grande transação para ele, então outros aplicativos podem usar a tabela em paralelo. Claro, você também pode fazer uma grande transação se quiser, então você terá a garantia de que o MySql executará "tudo ou nada", mas outros aplicativos provavelmente não serão capazes de usar o banco de dados durante a execução da transação.

Tenho uma tabela de 40 milhões de linhas e o script Python a atualiza em 3-4 horas.

Agora temos MySql JSON, então não precisamos mais de Python ou PHP, podemos fazer algo assim:

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

Parece simples e excelente. No entanto, sua velocidade é 10-20 vezes mais lenta do que a versão Python, e é uma transação única, portanto, outros aplicativos não podem modificar os dados da tabela em paralelo.

Portanto, se quisermos apenas duplicar a chave JSON em uma tabela de 40 milhões de linhas, não precisamos usar a tabela durante 30-40 horas. Não tem sentido.

Sobre a leitura de dados, pela minha experiência, o acesso direto ao campo JSON via JSON_EXTRACTin WHEREtambém é extremamente lento (muito mais lento do que TEXTcom uma LIKEcoluna não indexada). As colunas geradas virtuais têm um desempenho muito mais rápido, no entanto, se conhecermos nossa estrutura de dados de antemão, não precisamos de JSON, podemos usar colunas tradicionais. Quando usamos JSON onde é realmente útil, ou seja, quando a estrutura de dados é desconhecida ou muda com frequência (por exemplo, configurações de plug-in personalizado), a criação de colunas virtuais regularmente para quaisquer novas colunas possíveis não parece uma boa ideia.

Python e PHP tornam a validação JSON um encanto, então é questionável se precisamos de validação JSON no lado do MySql. Por que não validar também XML, documentos do Microsoft Office ou verificar a ortografia? ;)

Vitalii
fonte