2016-09-27 4 views
3

Ich habe eine Tabelle, die Daten in einer JSONB-Spalte speichert.Postgres-Tabelle mit JSONB-Daten abfragen

Nun, was ich tun möchte, ist, diese Tabelle abfragen und Datensätze abrufen, die bestimmte Werte für einen Schlüssel haben.

Dies funktioniert:

SELECT "documents".* 
FROM "documents" 
WHERE (data @> '{"type": "foo"}') 

Aber was ich will zu tun ist, um alle Zeilen in der Tabelle holen, welche Typen foo OR bar haben.

Ich habe versucht, dieses:

SELECT "documents".* 
FROM "documents" 
WHERE (data @> '{"type": ["foo", "bar"]}') 

Aber das scheint nicht zu funktionieren.

Ich habe auch versucht dies:

SELECT "documents".* 
FROM "documents" 
WHERE (data->'type' ?| array['foo', 'bar']) 

Welche funktioniert, aber wenn ich einen Schlüssel wie so data->'type' angeben nimmt es die dynamicity der Abfrage entfernt.

BTW, ich benutze Ruby on Rails mit Postgres, so dass alle Abfragen gehen . Dies ist, wie:

Document.where("data @> ?", query) 

Antwort

3

wenn ich einen Schlüssel wie so Daten angeben -> ‚Typ‘ nimmt es die dynamicity der Abfrage entfernt.

Ich verstehe Sie haben einen Gin Index für die Spalte data wie folgt definiert:

CREATE INDEX ON documents USING GIN (data); 

Der Index für diese Abfrage funktioniert:

EXPLAIN ANALYSE 
SELECT "documents".* 
FROM "documents" 
WHERE data @> '{"type": "foo"}'; 

                  QUERY PLAN               
------------------------------------------------------------------------------------------------------------------------------ 
Bitmap Heap Scan on documents (cost=30.32..857.00 rows=300 width=25) (actual time=0.639..0.640 rows=1 loops=1) 
    Recheck Cond: (data @> '{"type": "foo"}'::jsonb) 
    Heap Blocks: exact=1 
    -> Bitmap Index Scan on documents_data_idx (cost=0.00..30.25 rows=300 width=0) (actual time=0.581..0.581 rows=1 loops=1) 
     Index Cond: (data @> '{"type": "foo"}'::jsonb) 
Planning time: 7.928 ms 
Execution time: 0.841 ms 

aber nicht für diese:

EXPLAIN ANALYSE 
SELECT "documents".* 
FROM "documents" 
WHERE (data->'type' ?| array['foo', 'bar']); 

               QUERY PLAN             
----------------------------------------------------------------------------------------------------------- 
Seq Scan on documents (cost=0.00..6702.98 rows=300 width=25) (actual time=31.895..92.813 rows=2 loops=1) 
    Filter: ((data -> 'type'::text) ?| '{foo,bar}'::text[]) 
    Rows Removed by Filter: 299997 
Planning time: 1.836 ms 
Execution time: 92.839 ms 

Lösung 1. Verwenden Sie die Op

CREATE INDEX ON documents USING GIN ((data->'type')); 

EXPLAIN ANALYSE 
SELECT "documents".* 
FROM "documents" 
WHERE (data->'type' ?| array['foo', 'bar']); 

                  QUERY PLAN               
------------------------------------------------------------------------------------------------------------------------------ 
Bitmap Heap Scan on documents (cost=30.32..857.75 rows=300 width=25) (actual time=0.056..0.067 rows=2 loops=1) 
    Recheck Cond: ((data -> 'type'::text) ?| '{foo,bar}'::text[]) 
    Heap Blocks: exact=2 
    -> Bitmap Index Scan on documents_expr_idx (cost=0.00..30.25 rows=300 width=0) (actual time=0.035..0.035 rows=2 loops=1) 
     Index Cond: ((data -> 'type'::text) ?| '{foo,bar}'::text[]) 
Planning time: 2.951 ms 
Execution time: 0.108 ms 

Lösung 3. In der Tat ist dies eine Variante der Lösung 1:

EXPLAIN ANALYSE 
SELECT "documents".* 
FROM "documents" 
WHERE data @> '{"type": "foo"}' 
OR data @> '{"type": "bar"}'; 

                  QUERY PLAN                
------------------------------------------------------------------------------------------------------------------------------------ 
Bitmap Heap Scan on documents (cost=60.80..1408.13 rows=600 width=25) (actual time=0.222..0.233 rows=2 loops=1) 
    Recheck Cond: ((data @> '{"type": "foo"}'::jsonb) OR (data @> '{"type": "bar"}'::jsonb)) 
    Heap Blocks: exact=2 
    -> BitmapOr (cost=60.80..60.80 rows=600 width=0) (actual time=0.204..0.204 rows=0 loops=1) 
     -> Bitmap Index Scan on documents_data_idx (cost=0.00..30.25 rows=300 width=0) (actual time=0.144..0.144 rows=1 loops=1) 
       Index Cond: (data @> '{"type": "foo"}'::jsonb) 
     -> Bitmap Index Scan on documents_data_idx (cost=0.00..30.25 rows=300 width=0) (actual time=0.059..0.059 rows=1 loops=1) 
       Index Cond: (data @> '{"type": "bar"}'::jsonb) 
Planning time: 3.170 ms 
Execution time: 0.289 ms 

Lösung 2 einen zusätzlichen Index für (data->'type') erstellen: erator @> zweimal, wird der Index für beide Bedingungen verwendet werden , mit einem anderen Format der Bedingung, die bequemer sein kann, vom Client-Programm zu verwenden:

EXPLAIN ANALYSE 
SELECT "documents".* 
FROM "documents" 
WHERE data @> any(array['{"type": "foo"}', '{"type": "bar"}']::jsonb[]); 

                  QUERY PLAN               
------------------------------------------------------------------------------------------------------------------------------ 
Bitmap Heap Scan on documents (cost=60.65..1544.20 rows=600 width=26) (actual time=0.803..0.819 rows=2 loops=1) 
    Recheck Cond: (data @> ANY ('{"{\"type\": \"foo\"}","{\"type\": \"bar\"}"}'::jsonb[])) 
    Heap Blocks: exact=2 
    -> Bitmap Index Scan on documents_data_idx (cost=0.00..60.50 rows=600 width=0) (actual time=0.778..0.778 rows=2 loops=1) 
     Index Cond: (data @> ANY ('{"{\"type\": \"foo\"}","{\"type\": \"bar\"}"}'::jsonb[])) 
Planning time: 2.080 ms 
Execution time: 0.304 ms 
(7 rows) 

mehr in the documentation lesen.

+0

Vielen Dank für die Antwort @klin. Die Lösung 1 würde funktionieren, aber ich dachte über einen anderen Weg nach, coz Rails ist der API-Teil, und es kann Anfragen jeglicher Art geben, und ich möchte nicht in Pars Parsing gehen. Ich dachte also an einen saubereren Weg, der meiner Meinung nach da sein sollte, da dies nur eine elementare Operation ist. Was denken Sie? –

+0

Ich weiß was du meinst und deswegen habe ich über die zweite Lösung geschrieben. Es gibt keinen saubereren. – klin

+0

Ja, aber das Attribut kann sich ändern, es wird nicht immer Typ sein, also würde das Parsing wieder ins Bild kommen. –