PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Postgres 9.4 jsonb array sebagai tabel

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 dan value.

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 dan jsonb_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.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cara Memperbarui Banyak Kolom di PostgreSQL

  2. Berikan hak istimewa pada tabel mendatang di PostgreSQL?

  3. Daftar semua urutan dalam Postgres db 8.1 dengan SQL

  4. Nonaktifkan pemeriksaan kunci asing PostgreSQL untuk migrasi

  5. Penyatuan Koneksi PostgreSQL:Bagian 1 – Pro &Kontra