Os armazenamentos de documentos NoSQL podem ser ideais para gerenciar grandes quantidades de dados não estruturados. No entanto, algumas organizações trabalham com dados não estruturados, mas ainda querem os recursos que vêm com os bancos de dados SQL tradicionais. Por exemplo, agências de conteúdo de mídia ou notícias podem ter sites de alto tráfego centrados em grandes quantidades de conteúdo de texto e imagem. Embora precisem armazenar esses dados não estruturados, talvez não precisem realmente dos esquemas flexíveis ou da escalabilidade horizontal que vêm com os bancos de dados NoSQL. Em vez disso, precisam da facilidade de gerenciamento de banco de dados e da consistência que vem com um banco de dados relacional como o PostgreSQL.
É possível obter o melhor dos dois mundos? Sim.
Com seus tipos de dados destinados a suportar dados não estruturados, o PostgreSQL oferece um meio termo, permitindo que você aproveite os recursos NoSQL em um banco de dados relacional que é econômico e simples de gerenciar. Neste artigo, veremos como você pode usar os tipos de dados HStore e JSONB no PostgreSQL para trabalhar com dados não estruturados.
Antes de nos aprofundarmos, vamos dar uma breve olhada nas principais diferenças entre os bancos de dados SQL e NoSQL.
Compreensão de SQL versus NoSQL
Os bancos de dados SQL e NoSQL têm seus pontos fortes e fracos exclusivos. Tomar uma decisão informada sobre qual deles atenderá melhor às suas necessidades de dados depende de um sólido entendimento de suas diferenças.
Os bancos de dados SQL (relacionais), como o PostgreSQL e o MySQL, representam dados com uma estrutura clara e previsível em tabelas, linhas e colunas. Eles aderem às propriedades ACID (atomicidade, consistência, isolamento e durabilidade), que produzem uma base sólida para a integridade dos dados, garantindo que as transações do banco de dados sejam processadas de forma confiável.
Os bancos de dados SQL brilham quando a consistência e a integridade dos dados são cruciais, por exemplo, ao lidar com consultas complexas e sistemas transacionais (como nos aplicativos financeiros).
Por outro lado, os bancos de dados NoSQL (armazenamentos de documentos) atendem a conjuntos de dados grandes e variados, não necessariamente adequados para representação tabular. Exemplos de bancos de dados NoSQL são o MongoDB, o Cassandra e o Couchbase. Os bancos de dados NoSQL trabalham com esquemas flexíveis, permitindo que as estruturas de dados evoluam com o tempo. Eles também oferecem suporte à escalabilidade horizontal, distribuindo dados em vários servidores para melhorar o manuseio de grandes cargas de dados e alto tráfego.
Os bancos de dados NoSQL são frequentemente usados em aplicativos em que a escalabilidade é crucial, como para lidar com grandes quantidades de dados em aplicativos em tempo real ou grandes modelos de linguagem (LLMs). Os bancos de dados NoSQL também são benéficos ao lidar com estruturas de dados variadas e em evolução, pois permitem que as organizações se adaptem à medida que suas necessidades de dados mudam.
Por que você pode usar o PostgreSQL como um armazenamento de documentos?
O PostgreSQL é um banco de dados relacional, portanto, pode parecer pouco convencional considerá-lo uma opção para atender às necessidades de NoSQL. No entanto, sua situação pode ser um caso forte para usar o PostgreSQL como um armazenamento de documentos.
Se suas necessidades de armazenamento de dados forem diversas - exigindo armazenamento de dados estruturados e em conformidade com ACID e armazenamento de documentos flexíveis e sem esquema -, você poderá aproveitar o PostgreSQL para combinar modelos relacionais e não relacionais. Ou talvez você queira determinados recursos NoSQL, mas também queira as garantias de consistência de dados que vêm com as propriedades ACID. Por fim, como uma tecnologia madura com uma comunidade ativa, o PostgreSQL oferece suporte abrangente a SQL, indexação avançada e pesquisa de texto completo. Esses recursos - combinados com seus recursos NoSQL - fazem do PostgreSQL uma solução versátil de armazenamento de dados.
Limitações do uso do PostgreSQL para dados do tipo NoSQL
Apesar de sua versatilidade, o PostgreSQL tem certas limitações em comparação com os bancos de dados NoSQL tradicionais. Embora o PostgreSQL possa ser escalonado verticalmente, ele não suporta inerentemente o escalonamento horizontal ou dados distribuídos com fragmentação automática, recursos que os bancos de dados NoSQL normalmente oferecem. O PostgreSQL também não oferece otimizações para determinadas estruturas de dados NoSQL, como armazenamentos de colunas largas ou bancos de dados de gráficos. Por fim, o PostgreSQL não oferece consistência ajustável para otimizar o desempenho, o que pode ser obtido em alguns bancos de dados NoSQL.
Ao considerar o uso do PostgreSQL para conjuntos de dados grandes e não estruturados, saiba que essas limitações podem afetar o desempenho e sua capacidade de escalonamento. Além disso, a combinação de operações de dados SQL e NoSQL introduz complexidade. O planejamento cuidadoso e a compreensão de ambos os paradigmas o ajudarão a evitar possíveis armadilhas.
No entanto, com o entendimento e o caso de uso corretos, o PostgreSQL pode servir como uma ferramenta poderosa, oferecendo o melhor dos mundos SQL e NoSQL.
HStore e JSONB no PostgreSQL
Ao considerarmos as possibilidades de uso do PostgreSQL como uma solução NoSQL, encontramos três tipos de dados que oferecem funcionalidade semelhante à do NoSQL, mas cada um deles tem características e casos de uso exclusivos.
- Loja: Esse tipo de dados permite armazenar pares de valores-chave em um único valor do PostgreSQL. É útil para armazenar dados semiestruturados que não têm um esquema fixo.
- JSONB: Trata-se de uma representação binária de dados do tipo JSON. Ele pode armazenar estruturas mais complexas em comparação com o HStore e oferece suporte a todos os recursos JSON. O JSONB é indexável, o que o torna uma boa opção para grandes quantidades de dados.
- JSON: É semelhante ao JSONB, embora não tenha muitos dos recursos e eficiências do JSONB. O tipo de dados JSON armazena uma cópia exata do texto de entrada, que inclui espaço em branco e chaves duplicadas.
Mencionamos o tipo de dados JSON como uma opção válida para armazenar dados formatados em JSON quando você não precisa de todos os recursos fornecidos pelo JSONB. No entanto, nosso foco principal no restante deste artigo será o HStore e o JSONB.
HStore
A documentação do PostgreSQL descreve o HStore como útil quando você tem "linhas com muitos atributos que raramente são examinados, ou dados semiestruturados". Antes que você possa trabalhar com o tipo de dados HStore, certifique-se de habilitar a extensão HStore:
> CREATE EXTENSION hstore;
O HStore é representado como zero ou mais chaves => valores separados por vírgulas. A ordem dos pares não é significativa nem é retida de forma confiável na saída.
> SELECT 'foo => bar, prompt => "hello world", pi => 3.14'::hstore;
hstore
-----------------------------------------------------
"pi"=>"3.14", "foo"=>"bar", "prompt"=>"hello world"
(1 row)
Cada chave do HStore é exclusiva. Se uma declaração do HStore for feita com chaves duplicadas, apenas uma das duplicatas será armazenada, e não há garantia de qual será.
> SELECT 'key => value1, key => value2'::hstore;
hstore
-----------------
"key"=>"value1"
(1 row)
Com sua estrutura plana de chave-valor, o HStore oferece simplicidade e consulta rápida, o que o torna ideal para cenários diretos. No entanto, o HStore suporta apenas dados de texto e não suporta dados aninhados, o que o torna limitado para estruturas de dados complexas.
Por outro lado, o JSONB pode lidar com uma variedade maior de tipos de dados.
JSONB
O tipo de dados JSONB aceita texto de entrada formatado em JSON e, em seguida, armazena-o em um formato binário decomposto. Embora essa conversão torne a entrada um pouco lenta, o resultado é um processamento rápido e uma indexação eficiente. O JSONB não preserva o espaço em branco nem a ordem das chaves do objeto.
> SELECT '{"foo": "bar", "pi": 3.14, "nested": { "prompt": "hello", "count": 5 } }'::jsonb;
jsonb
-----------------------------------------------------------------------
{"pi": 3.14, "foo": "bar", "nested": {"count": 5, "prompt": "hello"}}
(1 row)
Se forem fornecidas chaves de objeto duplicadas, o último valor será mantido.
> SELECT '{"key": "value1", "key": "value2"}'::jsonb;
jsonb
-------------------
{"key": "value2"}
(1 row)
Como o JSONB oferece suporte a estruturas complexas e recursos completos de JSON, ele é a opção ideal para dados complexos ou aninhados, preferível ao HStore ou ao JSON. No entanto, o uso do JSONB apresenta alguma sobrecarga de desempenho e maior uso de armazenamento em comparação com o HStore.
Exemplos práticos: Trabalhando com HStore e JSONB
Vamos considerar alguns exemplos práticos para demonstrar como trabalhar com esses tipos de dados. Veremos a criação de tabelas, consultas e operações básicas e indexação.
Operações básicas do HStore
Como faria com qualquer outro tipo de dados, você pode definir campos em sua tabela de dados do PostgreSQL como um tipo de dados HStore.
> CREATE TABLE articles ( id serial primary key, title varchar(64), meta hstore );
A inserção de um registro com um atributo HStore tem a seguinte aparência:
> INSERT INTO articles (title, meta)
VALUES (
'Data Types in PostgreSQL',
'format => blog, length => 1350, language => English, license => "Creative Commons"');
> SELECT * FROM articles;
id | title | meta ----+--------------------------+------------------------------------------ 1 | Data Types in PostgreSQL | "format"=>"blog", "length"=>"1350", "license"=>"Creative Commons", "language"=>"English"(1 row)
Com os campos do HStore, você pode buscar pares de valores-chave específicos do campo, conforme especificado pelas chaves fornecidas por você:
> SELECT title, meta -> 'license' AS license, meta -> 'format' AS format FROM articles;
title | license | format
---------------------------------+------------------+------------
Data Types in PostgreSQL | Creative Commons | blog
Advanced Querying in PostgreSQL | None | blog
Scaling PostgreSQL | MIT | blog
PostgreSQL Fundamentals | Creative Commons | whitepaper
(4 rows)
Você também pode consultar com critérios baseados em valores específicos em um campo do HStore.
> SELECT id, title FROM articles WHERE meta -> 'license' = 'Creative Commons';
id | title
----+--------------------------
1 | Data Types in PostgreSQL
4 | PostgreSQL Fundamentals
(2 rows)
Às vezes, você pode querer consultar apenas as linhas que contêm uma chave específica no campo HStore. Por exemplo, a consulta a seguir retorna apenas as linhas em que o meta HStore contém a chave de nota. Para fazer isso, você usaria o operador ?
> SELECT title, meta->'note' AS note FROM articles WHERE meta ? 'note';
title | note
---------------------------------+-----------------
PostgreSQL Fundamentals | hold for review
Advanced Querying in PostgreSQL | needs edit
(2 rows)
Uma lista de operadores e funções úteis do HStore pode ser encontrada aqui. Por exemplo, você pode extrair as chaves de um HStore para uma matriz ou pode converter um HStore em uma representação JSON.
> SELECT title, akeys(meta) FROM articles where id=1;
title | akeys
--------------------------+----------------------------------
Data Types in PostgreSQL | {format,length,license,language}
(1 row)
> SELECT title, hstore_to_json(meta) FROM articles where id=1;
title | hstore_to_json
--------------------------+------------------------------------------------
Data Types in PostgreSQL | {"format": "blog", "length": "1350", "license": "Creative Commons", "language": "English"}
(1 row)
Operações básicas de JSONB
Trabalhar com o tipo de dados JSONB no PostgreSQL é simples. A criação de tabelas e a inserção de registros são assim:
> CREATE TABLE authors (id serial primary key, name varchar(64), meta jsonb);
> INSERT INTO authors (name, meta) VALUES ('Adam Anderson', '{ "active":true, "expertise": ["databases", "data science"], "country": "UK" }');
Observe que o campo meta jsonb é fornecido como uma string de texto no formato JSON. O PostgreSQL reclamará se o valor que você fornecer não for um JSON válido.
> INSERT INTO authors (name, meta) VALUES ('Barbara Brandini', '{ "this is not valid JSON" }');
ERROR: invalid input syntax for type json
Ao contrário do tipo HStore, o JSONB suporta dados aninhados.
> INSERT INTO authors (name, meta) VALUES ('Barbara Brandini', '{ "active":true, "expertise": ["AI/ML"], "country": "CAN", "contact": { "email": "barbara@example.com", "phone": "111-222-3333" } }');
Semelhante ao HStore, os campos JSONB podem ser recuperados parcialmente, apenas com determinadas chaves. Por exemplo:
> SELECT name, meta -> 'country' AS country FROM authors;
name | country ------------------+--------- Adam Anderson | "UK" Barbara Brandini | "CAN" Charles Cooper | "UK"(3 rows)
O tipo de dados JSONB tem muitos operadores que são semelhantes em uso ao HStore. Por exemplo, o seguinte uso do operador ? recupera apenas as linhas em que o campo meta contém a chave do contato.
> SELECT name, meta -> 'active' AS active, meta -> 'contact' AS contact FROM authors WHERE meta ? 'contact';
name | active | contact
------------------+--------+-----------------------------------------------
Barbara Brandini | true | {"email": "barbara@example.com", "phone": "111-222-3333"}
Charles Cooper | false | {"email": "charles@example.com"}
(2 rows)
Trabalhando com índices
De acordo com a documentação, o tipo de dados HStore "tem suporte a índices GiST e GIN para os operadores @>, ?, ?& e ?|". Para obter uma explicação detalhada das diferenças entre os dois tipos de índices, consulte aqui. A indexação para JSONB usa índices GIN para facilitar a pesquisa eficiente de chaves ou pares de valores-chave.
A instrução para criar um índice é como seria de se esperar:
> CREATE INDEX idx_hstore ON articles USING GIN(meta);
> CREATE INDEX idx_jsonb ON authors USING GIN(meta);
Estrutura SQL com flexibilidade NoSQL
Vamos revisitar o caso de uso original que mencionamos na introdução. Imagine uma agência de conteúdo de notícias que armazena seus artigos da mesma forma que faria com um armazenamento de documentos NoSQL. Talvez o artigo possa ser representado em JSON como uma matriz ordenada de objetos que representam seções, cada uma com conteúdo de texto, notações e formatação. Além disso, uma série de metadados está associada a cada artigo, e esses atributos de metadados são inconsistentes de um artigo para o outro.
A descrição acima encapsula a maior parte das necessidades de NoSQL da organização, mas tudo o mais sobre como ela gerencia e organiza seus dados se alinha estreitamente com um modelo de dados relacional.
Combinando os recursos NoSQL de um tipo de dados como o JSONB com os pontos fortes do SQL tradicional do PostgreSQL, a organização pode desfrutar de esquemas flexíveis e consultas rápidas em dados aninhados e, ao mesmo tempo, ser capaz de realizar operações conjuntas e impor relacionamentos de dados. Os tipos de dados HStore e JSONB do PostgreSQL oferecem opções poderosas para desenvolvedores que precisam da estrutura de um banco de dados relacional, mas que também precisam de armazenamento de dados no estilo NoSQL.
PostgreSQL em escala
Você deseja oferecer suporte ao armazenamento e à consulta de dados no estilo NoSQL e, ao mesmo tempo, permanecer dentro da estrutura de um banco de dados relacional tradicional? Talvez sua organização lide com documentos de forma semelhante à que descrevemos neste post. Ou talvez esteja procurando opções para lidar com o armazenamento de dados não estruturados para um modelo de linguagem grande (LLM) ou algum outro empreendimento de IA/ML.
O cluster PostgreSQL no Linode Marketplace oferece o modelo relacional e a estrutura de um banco de dados SQL, juntamente com a escalabilidade horizontal de um banco de dados NoSQL. Combine isso com o uso de tipos de dados HStore ou JSONB e você terá uma solução híbrida ideal para aproveitar os recursos NoSQL enquanto trabalha no PostgreSQL.
Comentários