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.