PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Tablica jsonb Postgres 9.4 jako tabela

Zapytanie

Brak definicji tabeli. Zakładając:

CREATE TABLE configuration (
  config_id serial PRIMARY KEY
, config jsonb NOT NULL
);

Aby znaleźć value i jego wiersz dla podanego oid i instance :

SELECT c.config_id, d->>'value' AS value
FROM   configuration c
     , jsonb_array_elements(config->'data') d  -- default col name is "value"
WHERE  d->>'oid'      = '1.3.6.1.4.1.7352.3.10.2.5.35.3'
AND    d->>'instance' = '0'
AND    d->>'value'   <> '1'

To jest niejawny LATERAL Przystąp. Porównaj:

  • Zapytanie o elementy tablicy wewnątrz typu JSON

2) Jaki jest najszybszy sposób na uzyskanie tabeli z 3 kolumnami oid? , instance i value.

Przypuszczam, że użyję jsonb_populate_recordset() , możesz podać typy danych w definicji tabeli. Zakładając text dla wszystkich:

CREATE TEMP TABLE data_pattern (oid text, value text, instance text);

Może to być również tabela utrwalona (nie tymczasowa). Ten dotyczy tylko bieżącej sesji. Następnie:

SELECT c.config_id, d.*
FROM   configuration c
     , jsonb_populate_recordset(NULL::data_pattern, c.config->'data') d

To wszystko. Pierwsze zapytanie przepisane:

SELECT c.config_id, d.*
FROM   configuration c
     , jsonb_populate_recordset(NULL::data_pattern, c.config->'data') d
WHERE  d.oid      = '1.3.6.1.4.1.7352.3.10.2.5.35.3'
AND    d.instance = '0'
AND    d.value   <> '1';

Ale to wolniej niż pierwsze zapytanie. Kluczem do wydajności przy większej tabeli jest obsługa indeksów:

Indeks

Możesz łatwo zindeksować znormalizowaną (przetłumaczoną) tabelę lub alternatywny układ, który zaproponowałeś w pytaniu. Indeksowanie bieżącego układu nie jest tak oczywiste, ale też możliwe. Aby uzyskać najlepszą wydajność, sugeruję indeks funkcjonalny tylko na data klucz z jsonb_path_ops klasa operatora. Zgodnie z dokumentacją:

Techniczna różnica między jsonb_ops i jsonb_path_ops GINindex polega na tym, że pierwsza z nich tworzy niezależne pozycje indeksu dla każdego klucza i wartości w danych, podczas gdy druga tworzy pozycje indeksu tylko dla każdej wartości w danych.

To powinno zdziałać cuda dla wydajności:

CREATE INDEX configuration_my_idx ON configuration
USING gin ((config->'data') jsonb_path_ops);

Można by się spodziewać, że zadziała tylko pełne dopasowanie elementu tablicy JSON, na przykład:

SELECT * FROM configuration
WHERE  (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
                            , "instance": "0", "value": "1234"}]';

Zwróć uwagę na notację tablicy JSON (z załączając [] ) o podanej wartości, co jest wymagane.

Ale elementy tablicy z podzbiorem kluczy działa również:

SELECT * FROM configuration
WHERE  (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
                            , "instance": "0"}]'

Najtrudniejsze jest włączenie pozornie niepodejrzanego dodanego predykatu value <> '1' . Należy zachować ostrożność, aby zastosować wszystkie predykaty do tego samego element tablicy. Możesz połączyć to z pierwszym zapytaniem:

SELECT c.*, d->>'value' AS value
FROM   configuration c
     , jsonb_array_elements(config->'data') d
WHERE  (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3", "instance": "0"}]'
AND    d->>'oid'      = '1.3.6.1.4.1.7352.3.10.2.5.35.3'  -- must be repeated
AND    d->>'instance' = '0'                               -- must be repeated
AND    d->>'value'   <> '1'                               -- here we can rule out

Voila.

Indeks specjalny

Jeśli Twój stół jest ogromny, decydującym czynnikiem może być wielkość indeksu. Możesz porównać wydajność tego specjalnego rozwiązania z indeksem funkcjonalnym:

Ta funkcja wyodrębnia tablicę Postgres zawierającą id-instance kombinacje z danego jsonb wartość:

CREATE OR REPLACE FUNCTION f_config_json2arr(_j jsonb)
  RETURNS text[] LANGUAGE sql IMMUTABLE AS
$func$
SELECT ARRAY(
   SELECT (elem->>'oid') || '-' || (elem->>'instance')
   FROM   jsonb_array_elements(_j) elem
   )
$func$

Na tej podstawie możemy zbudować indeks funkcjonalny:

CREATE INDEX configuration_conrfig_special_idx ON configuration
USING  gin (f_config_json2arr(config->'data'));

I oprzyj na tym zapytanie:

SELECT * FROM configuration
WHERE  f_config_json2arr(config->'data') @> '{1.3.6.1.4.1.7352.3.10.2.5.35.3-0}'::text[]

Pomysł polega na tym, że indeks powinien być znacznie mniejszy, ponieważ przechowuje tylko połączone wartości bez kluczy. tablica operator zawartości @> sam powinien działać podobnie do operatora zawierania jsonb @> . Nie spodziewam się dużej różnicy, ale byłbym bardzo zainteresowany, co jest szybsze.

Podobne do pierwszego rozwiązania w tej powiązanej odpowiedzi (ale bardziej specjalistyczne):

  • Indeks do znajdowania elementu w tablicy JSON

Poza tym:

  • Nie używałbym oid jako nazwę kolumny, ponieważ jest ona również używana do celów wewnętrznych w Postgresie.
  • Jeśli to możliwe, użyłbym zwykłej, znormalizowanej tabeli bez JSON.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Przechowuj i pobieraj obrazy w Postgresql za pomocą Java

  2. Naturalny sort obsługujący duże liczby

  3. Jak wyświetlić kod CREATE VIEW dla widoku w PostgreSQL?

  4. Python psycopg2 nie wstawia się do tabeli postgresql

  5. Zdobycie wszystkich budynków w zasięgu 5 mil od określonych współrzędnych