Kueri
Definisi tabel Anda tidak ada. Dengan asumsi:
CREATE TABLE configuration (
config_id serial PRIMARY KEY
, config jsonb NOT NULL
);
Untuk menemukan value
dan barisnya untuk oid
yang diberikan dan 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'
Itu adalah LATERAL
implicit implisit Ikuti. Bandingkan:
- Kueri untuk elemen array di dalam tipe JSON
2) Apa cara tercepat untuk mendapatkan tabel dengan 3 kolom
oid
,instance
danvalue.
Saya kira menggunakan jsonb_populate_recordset()
, maka Anda dapat memberikan tipe data dalam definisi tabel. Dengan asumsi text
untuk semua:
CREATE TEMP TABLE data_pattern (oid text, value text, instance text);
Bisa juga berupa tabel yang bertahan (non-temp). Yang ini hanya untuk sesi saat ini. Kemudian:
SELECT c.config_id, d.*
FROM configuration c
, jsonb_populate_recordset(NULL::data_pattern, c.config->'data') d
Itu saja. Kueri pertama ditulis ulang:
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';
Tapi itu lebih lambat daripada pertanyaan pertama. Kunci kinerja dengan tabel yang lebih besar adalah dukungan indeks:
Indeks
Anda dapat dengan mudah mengindeks tabel yang dinormalisasi (diterjemahkan) atau tata letak alternatif yang Anda usulkan dalam pertanyaan. Mengindeks tata letak Anda saat ini tidak begitu jelas, tetapi juga mungkin. Untuk kinerja terbaik, saya menyarankan indeks fungsional hanya pada data
kunci dengan jsonb_path_ops
kelas operator. Per dokumentasi:
Perbedaan teknis antara
jsonb_ops
danjsonb_path_ops
Indeks GIN adalah yang pertama membuat item indeks independen untuk setiap kunci dan nilai dalam data, sedangkan yang kedua membuat item indeks hanya untuk setiap nilai dalam data.
Ini akan menjadi keajaiban untuk kinerja:
CREATE INDEX configuration_my_idx ON configuration
USING gin ((config->'data') jsonb_path_ops);
Orang mungkin berharap bahwa hanya kecocokan lengkap untuk elemen array JSON yang akan berfungsi, seperti:
SELECT * FROM configuration
WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
, "instance": "0", "value": "1234"}]';
Perhatikan notasi larik JSON (dengan menyertakan []
) dari nilai yang diberikan, yang diperlukan.
Tetapi elemen larik dengan subset kunci bekerja juga:
SELECT * FROM configuration
WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
, "instance": "0"}]'
Bagian yang sulit adalah memasukkan predikat tambahan Anda yang tampaknya tidak mencurigakan value <> '1'
. Perhatian harus diberikan untuk menerapkan semua predikat ke sama elemen larik. Anda dapat menggabungkan ini dengan kueri pertama:
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 khusus
Jika meja Anda besar, ukuran indeks mungkin menjadi faktor penentu. Anda dapat membandingkan kinerja solusi khusus ini dengan indeks fungsional:
Fungsi ini mengekstrak larik Postgres dari oid-instance kombinasi dari jsonb
yang diberikan nilai:
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$
Kita dapat membangun indeks fungsional berdasarkan ini:
CREATE INDEX configuration_conrfig_special_idx ON configuration
USING gin (f_config_json2arr(config->'data'));
Dan dasarkan kueri di atasnya:
SELECT * FROM configuration
WHERE f_config_json2arr(config->'data') @> '{1.3.6.1.4.1.7352.3.10.2.5.35.3-0}'::text[]
Idenya adalah bahwa indeks harus jauh lebih kecil karena hanya menyimpan nilai gabungan tanpa kunci. larik operator penahanan @>
sendiri harus bekerja mirip dengan operator penahanan jsonb @>
. Saya tidak mengharapkan perbedaan besar, tetapi saya akan sangat tertarik mana yang lebih cepat.
Mirip dengan solusi pertama dalam jawaban terkait ini (tetapi lebih khusus):
- Indeks untuk menemukan elemen dalam larik JSON
Selain:
- Saya tidak akan menggunakan
oid
sebagai nama kolom karena itu juga digunakan untuk keperluan internal di Postgres. - Jika memungkinkan, saya akan menggunakan tabel biasa yang dinormalisasi tanpa JSON.