Todos os produtos
Search
Central de documentação

Hologres:JSON e JSONB

Última atualização: Jun 28, 2026

O Hologres oferece suporte aos tipos de dados semiestruturados JSON e JSONB para armazenar e consultar dados flexíveis e sem esquema. Este tópico aborda as diferenças entre os dois tipos, operadores e funções compatíveis, indexação GIN e integração com o Realtime Compute for Apache Flink.

JSON vs. JSONB: como escolher o tipo adequado

Ambos os tipos armazenam dados formatados em JSON, mas diferem no formato de armazenamento e nas características de desempenho.

JSON

JSONB

Formato de armazenamento

Texto simples

Binário decomposto

Velocidade de escrita

Rápida

Mais lenta (conversão adicional na escrita)

Velocidade de leitura

Mais lenta (reanálise a cada consulta)

Mais rápida (sem necessidade de reanálise)

Preservação exata do texto de entrada

Sim — espaços, ordem das chaves e chaves duplicadas são mantidos

Não — espaços removidos, chaves desduplicadas (prevalece o último valor), ordem das chaves não preservada

Suporte a índices GIN

Não

Sim (Hologres V1.1+)

Suporte a armazenamento colunar

Não

Sim (Hologres V1.3+)

Recomendação: utilize JSONB para a maioria das cargas de trabalho. O JSONB oferece consultas mais rápidas, suporte a índices GIN e armazenamento colunar. Use JSON apenas quando for necessário preservar o texto exato de entrada, incluindo a ordem das chaves, espaços e chaves duplicadas.

Comportamento de chaves duplicadas: quando a mesma chave aparece múltiplas vezes em um valor de entrada, o JSON retém todos os pares chave-valor (funções de processamento consideram o último valor como autoritativo), enquanto o JSONB mantém apenas o último valor.

Limites

Restrição

Detalhe

Tipo de dado JSON

Requer Hologres V0.9 ou posterior.

Índices GIN para JSONB

Requer Hologres V1.1 ou posterior.

Armazenamento colunar para JSONB

Requer Hologres V1.3 ou posterior. Compatível apenas com tabelas orientadas a colunas; tabelas orientadas a linhas não têm suporte. O armazenamento colunar é ativado somente quando a tabela possui 1.000 registros ou mais.

Índices GIN + armazenamento colunar

Mutuamente exclusivos a partir do Hologres V3.0.42 e V3.1.10. Quando ambos estão habilitados, os índices GIN não têm efeito. Utilize armazenamento colunar para campos não esparsos.

Funções sem suporte

json_each, jsonb_each, json_each_text, jsonb_each_text, json_extract_path, jsonb_extract_path, jsonb_to_record

Alternativa para json_extract_path e jsonb_extract_path: utilize o operador de caminho #>.

-- json_extract_path equivalent
SELECT '{"key":{"key1":"key1","key2":"key2"}}'::json #> '{"key","key1"}';

-- jsonb_extract_path equivalent
SELECT '{"key":{"key1":"key1","key2":"key2"}}'::jsonb #> '{"key","key1"}';

Para obter mais informações sobre como atualizar sua instância, consulte Atualizações de instância.

Operadores

Operadores de uso comum

Os seis operadores a seguir funcionam tanto com JSON quanto com JSONB.

**Operador**

**Tipo do operando direito**

**Descrição**

**Exemplo**

**Resultado**

->

int

Obtém um elemento de array JSON por índice (base 0; valores negativos contam a partir do final).

select '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json->2

{"c":"baz"}

->

text

Obtém um campo de objeto JSON pela chave.

select '{"a": {"b":"foo"}}'::json->'a'

{"b":"foo"}

->>

int

Obtém um elemento de array JSON como texto.

select '[1,2,3]'::json->>2

3

->>

text

Obtém um campo de objeto JSON como texto.

select '{"a":1,"b":2}'::json->>'b'

2

#>

text[]

Obtém um objeto JSON no caminho especificado.

select '{"a": {"b":{"c": "foo"}}}'::json#>'{a,b}'

{"c":"foo"}

#>>

text[]

Obtém um objeto JSON no caminho especificado como texto.

select '{"a":[1,2,3],"b":[4,5,6]}'::json#>>'{a,2}'

3

Operadores exclusivos do JSONB

Os operadores abaixo aplicam-se exclusivamente a dados JSONB e permitem verificações de contenção, testes de existência de chave, concatenação e exclusão.

**Operador**

**Tipo do operando direito**

**Descrição**

**Exemplo**

**Resultado**

@>

jsonb

Verifica se o valor à esquerda contém o caminho ou valor JSON à direita.

select '{"a":1, "b":2}'::jsonb @> '{"b":2}'::jsonb

true

<@

jsonb

Verifica se o caminho ou valor JSON à esquerda está contido no valor à direita.

select '{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonb

true

?

text

Verifica se uma string de chave ou elemento existe no valor JSONB.

select '{"a":1, "b":2}'::jsonb ? 'b'

true

`?

`

text[]

Verifica se alguma string de chave ou elemento no array existe no valor JSONB.

`select '{"a":1, "b":2, "c":3}'::jsonb ?

array['b', 'c']`

true

?&

text[]

Verifica se todas as strings do array existem no valor JSONB.

select '["a", "b"]'::jsonb ?& array['a', 'b']

true

`

`

jsonb

Concatena dois valores JSONB. Para objetos com a mesma chave, o valor do operando direito é utilizado. Este operador não é recursivo.

`select '["a", "b"]'::jsonb

'["c", "d"]'::jsonb`

["a", "b", "c", "d"]

-

text

Exclui a chave ou valor correspondente do operando esquerdo.

select '{"a": "b"}'::jsonb - 'a'

{}

-

text[]

Exclui múltiplas chaves ou valores correspondentes do operando esquerdo.

select '{"a": "b", "c": "d"}'::jsonb - '{a,c}'::text[]

{}

-

integer

Exclui o elemento do array na posição especificada (valores negativos contam a partir do final). Retorna um erro se o valor não for um array.

select '["a", "b"]'::jsonb - 1

["a"]

#-

text[]

Exclui o elemento no caminho especificado. Para arrays, inteiros negativos contam a partir do final.

select '["a", {"b":1}]'::jsonb #- '{1,b}'

["a", {}]

Funções

Funções de processamento

**Função**

**Tipo de retorno**

**Descrição**

**Exemplo**

**Resultado**

json_array_length(json) / jsonb_array_length(jsonb)

int

Retorna o número de elementos no array JSON mais externo.

select json_array_length('[1,2,3,{"f1":1,"f2":[5,6]},4]')

5

json_object_keys(json) / jsonb_object_keys(jsonb)

setof text

Retorna o conjunto de chaves no objeto JSON mais externo.

select json_object_keys('{"f1":"abc","f2":{"f3":"a", "f4":"b"}}')

f1f2

json_populate_record(base anyelement, from_json json) / jsonb_populate_record(base anyelement, from_json jsonb)

anyelement

Expande o objeto em from_json para uma linha correspondente ao tipo de registro definido por base. Se existir uma conversão (cast), ela será aplicada; caso contrário, o valor é representado como texto JSON.

select * from json_populate_record(null::myrowtype, '{"a": 1, "b": ["2", "a b"], "c": {"d": 4, "e": "a b c"}}')

`1

["2", "a b"]

{"d": 4, "e": "a b c"}`

json_populate_recordset(base anyelement, from_json json) / jsonb_populate_recordset(base anyelement, from_json jsonb)

setof anyelement

Expande o array de objetos mais externo em from_json para um conjunto de linhas correspondentes ao tipo de registro definido por base.

select * from json_populate_recordset(null::myrowtype, '[{"a":1,"b":2},{"a":3,"b":4}]')

`1

2``3

4`

json_array_elements(json) / jsonb_array_elements(jsonb)

setof json / setof jsonb

Expande um array JSON em um conjunto de valores JSON.

select * from json_array_elements('[1,true, [2,false]]')

1true[2,false]

json_array_elements_text(json) / jsonb_array_elements_text(jsonb)

setof text

Expande um array JSON em um conjunto de valores de texto.

select * from json_array_elements_text('["foo", "bar"]')

foobar

json_typeof(json) / jsonb_typeof(jsonb)

text

Retorna o tipo de dado do valor JSON mais externo como texto. Valores possíveis: OBJECT, ARRAY, STRING, NUMBER, BOOLEAN, NULL.

select json_typeof('-123.4')

number

json_strip_nulls(from_json json) / jsonb_strip_nulls(from_json jsonb)

json / jsonb

Remove todos os campos de objeto com valores nulos. Outros valores nulos são preservados.

select json_strip_nulls('[{"f1":1,"f2":null},2,null,3]')

[{"f1":1},2,null,3]

jsonb_set(target jsonb, path text[], new_value jsonb [, create_missing boolean])

jsonb

Substitui o valor em path dentro de target por new_value. Se create_missing for true (padrão) e o caminho não existir, new_value será inserido. Inteiros negativos em path contam a partir do final dos arrays.

select jsonb_set('[{"f1":1,"f2":null},2,null,3]', '{0,f1}','[2,3,4]', false)

[{"f1":[2,3,4],"f2":null},2,null,3]

jsonb_insert(target jsonb, path text[], new_value jsonb [, insert_after boolean])

jsonb

Insere new_value em path dentro de target. Para caminhos de array: insere antes do elemento alvo por padrão (insert_after = false); defina como true para inserir depois. Para caminhos de objeto: insere apenas se a chave não existir. Inteiros negativos em path contam a partir do final.

select jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"')

{"a": [0, "new_value", 1, 2]}

jsonb_pretty(from_json jsonb)

text

Retorna from_json como texto JSON indentado e legível.

select jsonb_pretty('[{"f1":1,"f2":null},2,null,3]')

[{ "f1": 1, "f2": null }, 2, null, 3]

jsonb_agg

jsonb

Agrega valores (incluindo nulos) em um array JSON.

Veja o exemplo abaixo.

jsonb_object_agg

jsonb

Agrega pares chave-valor em um objeto JSON. As chaves não podem ser nulas; os valores podem ser nulos.

Veja o exemplo abaixo.

is_valid_json(text)

boolean

Retorna true se a string de entrada for um JSON válido; caso contrário, retorna false. Valores ARRAY também são JSON válidos e podem ser gravados em colunas JSON ou JSONB. Requer Hologres V1.3.12 ou posterior.

Veja o exemplo abaixo.

Exemplo de jsonb_agg e jsonb_object_agg:

DROP TABLE IF EXISTS t;

CREATE TABLE t (
    k int PRIMARY KEY,
    class int NOT NULL,
    v text NOT NULL
);

INSERT INTO t (k, class, v)
SELECT
    (1 + s.v),
    CASE (s.v) < 3
    WHEN TRUE THEN 1
    ELSE 2
    END,
    chr(97 + s.v)
FROM generate_series(0, 5) AS s (v);

SELECT
    class,
    jsonb_agg(v ORDER BY v DESC) FILTER (WHERE v <> 'b') AS "jsonb_agg",
    jsonb_object_agg(v, k ORDER BY v DESC) FILTER (WHERE v <> 'e') AS "jsonb_object_agg(v, k)"
FROM t
GROUP BY class;

Resultado:

 class |    jsonb_agg    |  jsonb_object_agg(v, k)
-------+-----------------+--------------------------
     1 | ["c", "a"]      | {"a": 1, "b": 2, "c": 3}
     2 | ["f", "e", "d"] | {"d": 4, "f": 6}

Exemplo de is_valid_json:

DROP TABLE IF EXISTS test_json;

CREATE TABLE test_json (
    id int,
    json_strings text
);

INSERT INTO test_json
    VALUES (1, '{"a":2}'), (2, '{"a":{"b":{"c":1}}}'), (3, '{"a": [1,2,"b"]}');

INSERT INTO test_json
    VALUES (4, '{{}}'), (5, '{1:"a"}'), (6, '[1,2,3]');

SELECT
    id,
    json_strings,
    is_valid_json(json_strings)
FROM test_json
ORDER BY id;

Resultado:

 id | json_strings        | is_valid_json
----+---------------------+--------------
  1 | {"a":2}             | true
  2 | {"a":{"b":{"c":1}}} | true
  3 | {"a": [1,2,"b"]}    | true
  4 | {{}}                | false
  5 | {1:"a"}             | false
  6 | [1,2,3]             | true

Funções de análise (parsing)

**Função**

**Descrição**

**Exemplo**

**Resultado**

try_cast_to_jsonb(text)

Converte um valor de texto para JSONB. Retorna nulo se a entrada não for um JSONB válido. Requer Hologres V2.0.24 ou posterior.

select try_cast_to_jsonb('{"key": 1}')select try_cast_to_jsonb('{"key": 1')

{"key": 1}NULL

to_json(anyelement) / to_jsonb(anyelement)

Retorna o valor como um objeto JSON. Arrays e tipos compostos são convertidos recursivamente. Valores escalares utilizam uma função de conversão (cast) se disponível; caso contrário, são representados como texto JSON.

select to_json('Fred said "Hi."'::text)

"Fred said \"Hi.\""

array_to_json(anyarray [, pretty_bool])

Retorna um array como um array JSON. Arrays multidimensionais produzem arrays JSON aninhados. Quando pretty_bool é true, quebras de linha são adicionadas entre os elementos de nível superior.

select array_to_json('{{1,5},{99,100}}'::int[])

[[1,5],[99,100]]

json_build_array(VARIADIC "any") / jsonb_build_array(VARIADIC "any")

Constrói um array JSON a partir de uma lista variável de argumentos. Os argumentos podem ser de tipos diferentes.

select json_build_array(1,2,'3',4,5)

[1, 2, "3", 4, 5]

json_build_object(VARIADIC "any") / jsonb_build_object(VARIADIC "any")

Constrói um objeto JSON a partir de uma lista variável de argumentos alternados de chave e valor.

select json_build_object('foo',1,'bar',2)

{"foo": 1, "bar": 2}

json_object(text[]) / jsonb_object(text[])

Constrói um objeto JSON a partir de um array de texto. Aceita um array unidimensional com um número par de membros (pares chave-valor alternados) ou um array bidimensional onde cada array interno é um par chave-valor.

select json_object('{a, 1, b, "def", c, 3.5}')

{"a": "1", "b": "def", "c": "3.5"}

json_object(keys text[], values text[]) / jsonb_object(keys text[], values text[])

Constrói um objeto JSON a partir de dois arrays separados de chaves e valores.

select json_object('{a, b}', '{1,2}')

{"a": "1", "b": "2"}

Indexação de campos JSONB

O Hologres V1.1 e versões posteriores suportam índices GIN e índices B-tree em campos JSONB para acelerar consultas. Crie índices em campos JSONB em vez de campos JSON, pois índices GIN não estão disponíveis para JSON.

Índices GIN para JSONB são adequados para campos JSONB esparsos. Para campos não esparsos, prefira a otimização de armazenamento colunar do JSONB. A partir do Hologres V3.0.42 e V3.1.10, índices GIN e armazenamento colunar não podem ser usados simultaneamente — quando ambos estiverem habilitados, os índices GIN não terão efeito.

Duas classes de operadores de índice GIN estão disponíveis:

  • jsonb_ops (padrão): cria uma entrada de índice para cada chave e valor. Suporta os operadores ?, ?|, ?& e @>.

  • jsonb_path_ops: cria uma entrada de índice apenas para cada valor. Suporta somente o operador @>.

-- Create a GIN index using jsonb_ops (default)
CREATE INDEX idx_name ON table_name USING gin (idx_col);

-- Create a GIN index using jsonb_path_ops
CREATE INDEX idx_name ON table_name USING gin (idx_col jsonb_path_ops);

Operadores nativos do PostgreSQL

Índices GIN nativos do PostgreSQL exigem uma reverificação de dados após a recuperação, o que pode limitar as melhorias no desempenho da consulta. Os exemplos abaixo demonstram ambas as classes de operadores.

Exemplo: índice jsonb_ops com consulta de existência de chave

-- 1. Create a table.
BEGIN;
DROP TABLE IF EXISTS json_table;
CREATE TABLE IF NOT EXISTS json_table
(
    id INT,
    j  jsonb
);
COMMIT;

-- 2. Create a GIN index using jsonb_ops.
CREATE INDEX index_json ON json_table USING GIN(j);

-- 3. Insert data.
INSERT INTO json_table VALUES
    (1, '{"key1": 1, "key2": [1, 2], "key3": {"a": "b"}}'),
    (1, '{"key1": 1}'),
    (2, '{"key2": [1, 2], "key3": {"a": "b"}}');

-- 4. Query rows where key1 exists.
SELECT * FROM json_table WHERE j ? 'key1';

Resultado:

 id |                        j
----+-------------------------------------------------
  1 | {"key1": 1, "key2": [1, 2], "key3": {"a": "b"}}
  1 | {"key1": 1}

Execute EXPLAIN para confirmar o uso do índice:

EXPLAIN SELECT * FROM json_table WHERE j ? 'key1';
QUERY PLAN
Gather  (cost=0.00..0.26 rows=1000 width=12)
  ->  Local Gather  (cost=0.00..0.23 rows=1000 width=12)
        ->  Decode  (cost=0.00..0.23 rows=1000 width=12)
              ->  Bitmap Heap Scan on json_table  (cost=0.00..0.13 rows=1000 width=12)
                    Recheck Cond: (j ? 'key1'::text)
                    ->  Bitmap Index Scan on index_json  (cost=0.00..0.00 rows=0 width=0)
                          Index Cond: (j ? 'key1'::text)
Optimizer: HQO version 1.3.0

A etapa Bitmap Index Scan confirma que o índice foi utilizado.

Exemplo: índice jsonb_path_ops com consulta de contenção

-- 1. Create a table.
BEGIN;
DROP TABLE IF EXISTS json_table;
CREATE TABLE IF NOT EXISTS json_table
(
    id INT,
    j  jsonb
);
COMMIT;

-- 2. Create a GIN index using jsonb_path_ops.
CREATE INDEX index_json ON json_table USING GIN(j jsonb_path_ops);

-- 3. Insert 1,000,000 rows.
INSERT INTO json_table (
    SELECT
        i,
        ('{
            "key1": "'||i||'"
            ,"key2": "'||i%100||'"
            ,"key3": "'||i%1000||'"
            ,"key4": "'||i%10000||'"
            ,"key5": "'||i%100000||'"
        }')::jsonb
    FROM generate_series(1, 1000000) i
);

-- 4. Query rows containing '{"key1": "10"}'.
SELECT * FROM json_table WHERE j @> '{"key1": "10"}'::JSONB;

Resultado:

 id |                                   j
----+------------------------------------------------------------------------
 10 | {"key1": "10", "key2": "10", "key3": "10", "key4": "10", "key5": "10"}
(1 row)

Execute EXPLAIN para confirmar o uso do índice:

EXPLAIN SELECT * FROM json_table WHERE j @> '{"key1": "10"}'::JSONB;
                                            QUERY PLAN
-------------------------------------------------------------------------------------------
 Gather  (cost=0.00..0.26 rows=1000 width=12)
   ->  Local Gather  (cost=0.00..0.23 rows=1000 width=12)
         ->  Decode  (cost=0.00..0.23 rows=1000 width=12)
               ->  Bitmap Heap Scan on json_table  (cost=0.00..0.13 rows=1000 width=12)
                     Recheck Cond: (j @> '{"key1": "10"}'::jsonb)
                     ->  Bitmap Index Scan on index_json  (cost=0.00..0.00 rows=0 width=0)
                           Index Cond: (j @> '{"key1": "10"}'::jsonb)
 Optimizer: HQO version 1.3.0
(8 rows)

Operadores do Hologres

O Hologres fornece duas classes adicionais de operadores — jsonb_holo_ops e jsonb_holo_path_ops — que eliminam a etapa de reverificação de dados exigida pelos índices GIN nativos do PostgreSQL, melhorando o desempenho das consultas.

jsonb_holo_ops e jsonb_holo_path_ops suportam comprimentos de índice de 1 a 127 bytes. Valores de índice superiores a 127 bytes são truncados, e campos truncados exigem uma reverificação de dados. Execute EXPLAIN ANALYZE para verificar se ocorre uma reverificação.
  • jsonb_holo_ops: equivalente a jsonb_ops. Suporta os operadores ?, ?|, ?& e @>.

  • jsonb_holo_path_ops: equivalente a jsonb_path_ops. Suporta somente o operador @>.

Exemplo: índice jsonb_holo_ops

-- 1. Create a table.
BEGIN;
DROP TABLE IF EXISTS json_table;
CREATE TABLE IF NOT EXISTS json_table
(
    id INT,
    j  jsonb
);
COMMIT;

-- 2. Create a GIN index using jsonb_holo_ops.
CREATE INDEX index_json ON json_table USING GIN(j jsonb_holo_ops);

-- 3. Insert data.
INSERT INTO json_table VALUES
    (1, '{"key1": 1, "key2": [1, 2], "key3": {"a": "b"}}'),
    (1, '{"key1": 1}'),
    (2, '{"key2": [1, 2], "key3": {"a": "b"}}');

-- 4. Query rows where key1 exists.
SELECT * FROM json_table WHERE j ? 'key1';

Resultado:

 id |                        j
----+-------------------------------------------------
  1 | {"key1": 1}
  1 | {"key1": 1, "key2": [1, 2], "key3": {"a": "b"}}
(2 rows)

Exemplo: índice jsonb_holo_path_ops

-- 1. Create a table.
BEGIN;
DROP TABLE IF EXISTS json_table;
CREATE TABLE IF NOT EXISTS json_table
(
    id INT,
    j  jsonb
);

-- 2. Create a GIN index using jsonb_holo_path_ops.
CREATE INDEX index_json ON json_table USING GIN(j jsonb_holo_path_ops);

-- 3. Insert 1,000,000 rows.
INSERT INTO json_table (
    SELECT
        i,
        ('{
            "key1": "'||i||'"
            ,"key2": "'||i%100||'"
            ,"key3": "'||i%1000||'"
            ,"key4": "'||i%10000||'"
            ,"key5": "'||i%100000||'"
        }')::jsonb
    FROM generate_series(1, 1000000) i
);

-- 4. Query rows containing '{"key1": "10"}'.
SELECT * FROM json_table WHERE j @> '{"key1": "10"}'::JSONB;

Resultado:

 id |                                   j
----+------------------------------------------------------------------------
 10 | {"key1": "10", "key2": "10", "key3": "10", "key4": "10", "key5": "10"}
(1 row)

Importar dados JSONB do Realtime Compute for Apache Flink

Ao importar dados JSON do Realtime Compute for Apache Flink para o Hologres, os tipos de campo devem corresponder aos tipos suportados por cada sistema:

  • Tabelas de origem e resultado do Flink: defina campos JSON como VARCHAR.

  • Tabelas internas do Hologres: defina campos JSON como JSONB.

Para obter o mapeamento completo de tipos de dados, consulte Mapeamentos de tipos de dados entre Realtime Compute for Apache Flink e Hologres.

Etapa 1: Crie a tabela interna do Hologres com uma coluna JSONB.

BEGIN;
DROP TABLE IF EXISTS holo_internal_table;
CREATE TABLE IF NOT EXISTS holo_internal_table
(
    id      BIGINT NOT NULL,
    message JSONB  NOT NULL
);
CALL set_table_property('holo_internal_table', 'distribution_key', 'id');
COMMIT;

Etapa 2: Crie as tabelas de origem e resultado do Flink usando VARCHAR para o campo JSON e, em seguida, grave os dados no Hologres.

CREATE TEMPORARY TABLE randomSource (
    id      BIGINT,
    message VARCHAR
)
WITH ('connector' = 'datagen');

CREATE TEMPORARY TABLE sink_holo (
    id      BIGINT,
    message VARCHAR
)
WITH (
    'connector' = 'hologres',
    'dbname'    = '<yourDBname>',         -- Hologres database name
    'tablename' = '<holo_internal_table>', -- Target Hologres table
    'username'  = '<yourUsername>',       -- Alibaba Cloud AccessKey ID
    'password'  = '<yourPassword>',       -- Alibaba Cloud AccessKey secret
    'endpoint'  = '<yourEndpoint>'        -- VPC endpoint of your Hologres instance
);

INSERT INTO sink_holo
SELECT
    1,
    '{"k":"v"}'
FROM randomSource;

Armazenamento colunar para dados JSONB

Índices GIN otimizam o desempenho da consulta na camada de computação, mas ainda exigem a varredura completa do conteúdo JSON durante a execução. O Hologres V1.3 e versões posteriores oferecem armazenamento colunar para dados JSONB, realizando a otimização na camada de armazenamento. Os dados JSONB são armazenados em colunas, assim como dados estruturados, o que melhora a eficiência de compactação e acelera as consultas.

Para detalhes de configuração, consulte Acelerar consultas JSONB.