JSONB un JSON superior en PostgreSQL

Hace unos días me puse a trabajar con el tipo de dato JSONB de PostgreSQL, nuevo desde la versión 9.4, el mismo me ha resultado fantástico y superior a su primo JSON presente en PostgreSQL desde la versión 9.2, muestra evidente de la evolución del gestor hacia funcionalidades y características cada vez mejor, y al nivel de los requerimientos de la actualidad.

Comencemos con algunas pruebas para ver las ventajas de este nuevo tipo de dato:

Creamos dos tablas similares, solo cambia el tipo de dato:


create table tablajson (atributo JSON);
create table tablajsonb (atributo JSONB);

Se insertaron un total de 100000 tuplas.

INSERT INTO tablajsonb

SELECT row_to_json(consulta)::JSONB FROM (SELECT 'Nombre'||round((random() * 100)::numeric,0)::text||' Apellido'||round((random() * 100)::numeric,0)::text as nombre_apellidos,

round((random() * 100)::numeric,0) as edad,round((random() * 9)::numeric ,2)as porciento FROM generate_series(1,100000) ) consulta;

INSERT INTO tablajson

SELECT row_to_json(consulta)::json FROM (SELECT 'Nombre'||round((random() * 100)::numeric,0)::text||' Apellido'||round((random() * 100)::numeric,0)::text as nombre_apellidos,

round((random() * 100)::numeric,0) as edad,round((random() * 9)::numeric ,2)as porciento FROM generate_series(1,100000) ) consulta;

Soporte de operadores

JSONB soporta los mismo operadores de JSON:

Operador Descripción
-> Get JSON array element (indexed from zero)
-> Get JSON object field by key
->> Get JSON array element as text
->> Get JSON object field as text
#> Get JSON object at specified path
#>> Get JSON object at specified path as text

y JSONB además soporta los básicos del gestor:

Operator Description
< less than
> greater than
<= less than or equal to
>= greater than or equal to
= equal
<> or != not equal

Por ejemplo si ejecutamos para JSONB la consulta:

select atributo->'edad'::text,atributo->'nombre_apellidos' from tablajsonb where atributo->'edad'::text='0'

obtenemos:

“0”;””Nombre29 Apellido76″”
“0”;””Nombre62 Apellido76″”
“0”;””Nombre42 Apellido69″”
“0”;””Nombre49 Apellido77″”
“0”;””Nombre38 Apellido60″”
“0”;””Nombre81 Apellido82″”

 

y si ejecutamos la misma consulta para JSON:

select atributo->'edad'::text,atributo->'nombre_apellidos' from tablajson where atributo->'edad'::text='0'

obtenemos:

ERROR: el operador no existe: json = unknown
LINE 1: …e_apellidos’ from tablajson where atributo->’edad’::text=’0′
^
HINT: Ningún operador coincide con el nombre y el tipo de los argumentos. Puede ser necesario agregar conversiones explícitas de tipos.

También posee otros operadores específicos que te permite obtener valores dentro del JSON sin necesidad de utilizar funciones para obtener dichos valores.

Operator Description
@> Does the left JSON value contain within it the right value?
<@ Is the left JSON value contained within the right value?
? Does the key/element string exist within the JSON value?
?| Do any of these key/element strings exist?
?& Do all of these key/element strings exist?

 

Ejecutamos la consulta:

select atributo->'edad'::text,atributo->'nombre_apellidos' from tablajsonb where atributo @> '{"nombre_apellidos":"Nombre49 Apellido77"}'::jsonb

Obtenemos:

“0”;””Nombre49 Apellido77″”
“70”;””Nombre49 Apellido77″”
“52”;””Nombre49 Apellido77″”
“16”;””Nombre49 Apellido77″”
“38”;””Nombre49 Apellido77″”

 

 

Soporte para Índices

Específicamente el tipo de índice GIN es utilizado para indexar los JOSNB, por ejemplo:

CREATE INDEX indice1 ON tablajsonb   USING gin (atributo);

Tiempo y plan de ejecución con índice:

EXPLAIN ANALYZE
select atributo->'edad'::text,atributo->'nombre_apellidos' from tablajsonb where atributo @> '{"nombre_apellidos":"Nombre49 Apellido77"}'::jsonb

Obtenemos:

“Bitmap Heap Scan on tablajsonb (cost=20.77..339.16 rows=100 width=97) (actual time=1.000..1.118 rows=12 loops=1)”
” Recheck Cond: (atributo @> ‘{“nombre_apellidos”: “Nombre49 Apellido77″}’::jsonb)”
” Heap Blocks: exact=12″
” -> Bitmap Index Scan on indice1 (cost=0.00..20.75 rows=100 width=0) (actual time=0.937..0.937 rows=12 loops=1)”
” Index Cond: (atributo @> ‘{“nombre_apellidos”: “Nombre49 Apellido77″}’::jsonb)”
“Planning time: 0.304 ms”
“Execution time: 1.241 ms”

Tiempo y plan de ejecución sin índice:

“Seq Scan on tablajsonb (cost=0.00..2863.50 rows=100 width=97) (actual time=0.285..35.675 rows=12 loops=1)” ” Filter: (atributo @> ‘{“nombre_apellidos”: “Nombre49 Apellido77″}’::jsonb)”
” Rows Removed by Filter: 99988″
“Planning time: 1.170 ms”
“Execution time: 35.720 ms”

Se puede observar una diferencia notable. También se puede Crear índices parciales como:

CREATE INDEX indice2 on tablajsonb USING gin (atributo) where atributo @> '{"nombre_apellidos":"Nombre49 Apellido77"}'::jsonb ;

Bueno que con todo esto de los operadores e indices se pueden hacer algunas cosas beneficiosas y mas rápidas para las soluciones que utilicen datos en formato JSON, pues como vieron anteriormente tiene sus ventajas el JSONB, tampoco quiere decir que sea la solucion a todo, pero desde algun punto de vista tiene sus ventajas.

Parte 2

Saludos y espero que les sea útil :D.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s