Untuk meningkatkan kinerja kueri data JSONB, Hologres V1.3 dan versi yang lebih baru mendukung optimasi penyimpanan berorientasi kolom untuk tipe JSONB. Fitur ini dapat mengurangi ukuran penyimpanan dan mempercepat kueri. Topik ini menjelaskan cara menggunakan columnar JSONB di Hologres.
Prinsip columnar JSONB
Seperti yang ditunjukkan pada gambar berikut, setelah Anda mengaktifkan optimasi penyimpanan berorientasi kolom untuk JSONB, sistem secara otomatis mengonversi kolom JSONB menjadi format penyimpanan berorientasi kolom bertipe kuat di lapisan dasar. Saat Anda melakukan kueri terhadap nilai tertentu dalam data JSONB, sistem dapat langsung mengakses kolom yang sesuai, sehingga meningkatkan kinerja kueri. Di sisi lain, karena nilai-nilai dalam data JSONB disimpan dalam format berorientasi kolom, mereka dapat mencapai efisiensi penyimpanan dan kompresi yang sama seperti data terstruktur biasa. Hal ini mengurangi biaya penyimpanan dan meningkatkan efektivitas biaya.
Optimasi penyimpanan berorientasi kolom untuk JSONB tidak berlaku untuk tipe data JSON.

Batasan
-
Untuk kinerja optimal, kami menyarankan Anda melakukan upgrade instans Hologres ke V1.3.37 atau versi yang lebih baru sebelum menggunakan fitur columnar JSONB. Untuk meminta upgrade, lihat Common errors when upgrade preparation fails atau bergabung dengan grup DingTalk Hologres. Untuk informasi selengkapnya, lihat How to get more online support?.
-
Optimasi berorientasi kolom untuk JSONB hanya berlaku untuk tabel berorientasi kolom. Selain itu, optimasi hanya dipicu setelah tabel berisi minimal 1.000 baris.
-
Saat ini, hanya operator berikut yang mendukung optimasi penyimpanan berorientasi kolom. Penggunaan operator yang tidak didukung dalam kueri dapat menurunkan kinerja kueri.
Operator
Tipe operan kanan
Deskripsi
Operasi dan hasil
->
text
Mengambil bidang objek JSON berdasarkan kunci.
-
Contoh:
select '{"a": {"b":"foo"}}'::json->'a' -
Hasil:
{"b":"foo"}
->>
text
Mengambil bidang objek JSON sebagai TEXT.
-
Contoh:
select '{"a":1,"b":2}'::json->>'b' -
Hasil:
2
-
Menggunakan columnar JSONB
Aktifkan columnar JSONB
Gunakan pernyataan berikut untuk mengaktifkan optimasi penyimpanan berorientasi kolom pada kolom JSONB tertentu dalam sebuah tabel.
-- Aktifkan optimasi penyimpanan berorientasi kolom untuk kolom tertentu dalam tabel tertentu.
ALTER TABLE <table_name> ALTER COLUMN <column_name> SET (enable_columnar_type = ON);
table_name adalah nama tabel. column_name adalah nama kolom.
-
Setelah Anda mengaktifkan optimasi penyimpanan berorientasi kolom untuk JSONB, sistem akan mengonversi data historis ke format penyimpanan berorientasi kolom selama proses compaction. Konversi selesai setelah compaction selesai.
-
Compaction mengonsumsi sumber daya sistem, seperti memori. Kami menyarankan Anda melakukan operasi ini selama jam sepi. Anda dapat menjalankan perintah
vacuum table_name;untuk memaksa compaction. Proses compaction selesai setelah perintah vacuum selesai dijalankan. -
Setelah compaction selesai, data baru yang ditulis akan disimpan dalam format berorientasi kolom.
Aktifkan inferensi tipe DECIMAL
Sebelum mengaktifkan inferensi tipe DECIMAL, pastikan optimasi penyimpanan berorientasi kolom untuk JSONB sudah diaktifkan.
Hologres V2.0.11 dan versi yang lebih baru mendukung optimasi penyimpanan berorientasi kolom untuk data DECIMAL. Pertimbangkan data JSON berikut sebagai contoh:
{
"name":"Mike",
"statistical_period":"2023-01-01 00:00:00+08",
"balance":123.45
}
Setelah Anda mengaktifkan inferensi tipe DECIMAL, nilai balance juga mendukung optimasi berorientasi kolom. Gunakan pernyataan berikut untuk mengaktifkan fitur ini:
-- Aktifkan optimasi berorientasi kolom untuk nilai DECIMAL dalam kolom tertentu di tabel tertentu.
ALTER TABLE <table_name> ALTER COLUMN <column_name> SET (enable_decimal = ON);
table_name adalah nama tabel. column_name adalah nama kolom.
Memeriksa status columnar JSONB
Gunakan pernyataan berikut untuk memeriksa status columnar JSONB suatu tabel.
-
Perintah berikut didukung di Hologres V1.3.37 dan versi yang lebih baru.
CatatanDi Hologres V2.0.17 dan versi sebelumnya, perintah ini hanya dapat menampilkan tabel dalam skema
public. Mulai dari V2.0.18, perintah ini dapat menampilkan status tabel di skema lain.-- Di V2.0.17 dan versi sebelumnya, Anda hanya dapat mengkueri tabel dalam skema public. Di V2.0.18 dan versi yang lebih baru, Anda dapat mengkueri tabel di skema lain. SELECT * FROM hologres.hg_column_options WHERE schema_name='<schema_name>' AND table_name = '<table_name>';schema_name adalah nama skema, dan table_name adalah nama tabel.
-
Untuk Hologres V1.3.10 hingga V1.3.36, gunakan perintah berikut.
SELECT DISTINCT a.attnum as num, a.attname as name, format_type(a.atttypid, a.atttypmod) as type, a.attnotnull as notnull, com.description as comment, coalesce(i.indisprimary,false) as primary_key, def.adsrc as default, a.attoptions FROM pg_attribute a JOIN pg_class pgc ON pgc.oid = a.attrelid LEFT JOIN pg_index i ON (pgc.oid = i.indrelid AND i.indkey[0] = a.attnum) LEFT JOIN pg_description com on (pgc.oid = com.objoid AND a.attnum = com.objsubid) LEFT JOIN pg_attrdef def ON (a.attrelid = def.adrelid AND a.attnum = def.adnum) WHERE a.attnum > 0 AND pgc.oid = a.attrelid AND pg_table_is_visible(pgc.oid) AND NOT a.attisdropped AND pgc.relname = '<table_name>' ORDER BY a.attnum;table_name adalah nama tabel.
-
Contoh hasil:
Dalam hasil tersebut, jika properti attoptions atau option untuk suatu kolom bernilai
enable_columnar_type = ON, hal ini menunjukkan bahwa konfigurasi berhasil.num | name | type | notnull | comment | primary_key | default | attoptions ------+------+--------------------------+---------+---------+-------------+---------+------------------------------ 1 | ds | timestamp with time zone | f | | f | | 2 | tags | jsonb | f | | f | | {enable_columnar_type=on} (2 rows)
Nonaktifkan columnar JSONB
Gunakan perintah berikut untuk menonaktifkan optimasi penyimpanan berorientasi kolom pada kolom JSONB tertentu dalam sebuah tabel.
-- Nonaktifkan optimasi penyimpanan berorientasi kolom untuk kolom tertentu dalam tabel tertentu.
ALTER TABLE <table_name> ALTER COLUMN <column_name> SET (enable_columnar_type = OFF);
table_name adalah nama tabel. column_name adalah nama kolom.
-
Setelah Anda menonaktifkan optimasi penyimpanan berorientasi kolom untuk JSONB, sistem akan mengonversi data historis kembali ke format penyimpanan JSONB standar selama proses compaction. Konversi selesai setelah compaction selesai.
-
Compaction mengonsumsi sumber daya sistem, seperti memori. Kami menyarankan Anda melakukan operasi ini selama jam sepi. Anda dapat menjalankan perintah
vacuum table_name;untuk memaksa compaction. Proses compaction selesai setelah perintah vacuum selesai dijalankan. -
Setelah compaction selesai, data baru yang ditulis akan disimpan dalam format JSONB standar.
Nonaktifkan inferensi tipe DECIMAL
Untuk menonaktifkan inferensi tipe DECIMAL pada kolom tertentu, gunakan perintah berikut.
-- Nonaktifkan optimasi berorientasi kolom untuk nilai DECIMAL dalam kolom tertentu di tabel tertentu.
ALTER TABLE <table_name> ALTER COLUMN <column_name> SET (enable_decimal = OFF);
table_name adalah nama tabel. column_name adalah nama kolom.
Menonaktifkan inferensi tipe DECIMAL akan segera memicu compaction untuk mengonversi data DECIMAL yang sebelumnya dioptimalkan kembali ke format aslinya.
Menetapkan indeks bitmap
Di Hologres, properti bitmap_columns menentukan indeks bitmap, yaitu struktur indeks independen yang terpisah dari penyimpanan data. Indeks ini menggunakan struktur vektor bitmap untuk mempercepat perbandingan kesamaan, sehingga memungkinkan pemfilteran kesamaan data yang cepat dalam blok file. Mulai dari V2.0, Hologres mendukung penyetelan indeks bitmap untuk kolom JSONB yang telah diaktifkan penyimpanan berorientasi kolomnya. Setelah columnar JSONB diaktifkan, sistem mengurai data menjadi tujuh tipe data: int, int[], bigint, bigint[], text, text[], dan jsonb. Saat indeks bitmap diaktifkan, sistem membangun indeks bitmap untuk data yang diinferensikan sebagai tipe int, int[], bigint, bigint[], text, dan text[].
Sintaksnya adalah sebagai berikut:
call set_table_property('<table_name>', 'bitmap_columns', '[<columnName>{:[on|off]}[,...]]');
Parameter:
|
Parameter |
Deskripsi |
|
table_name |
Nama tabel. |
|
columnName |
Nama kolom. |
|
on |
Mengaktifkan indeks bitmap untuk bidang yang ditentukan. Penting
Anda hanya dapat menetapkan indeks bitmap untuk kolom JSONB yang telah diaktifkan penyimpanan berorientasi kolomnya. |
|
off |
Menonaktifkan indeks bitmap untuk bidang yang ditentukan. |
Contoh
-
Buat tabel.
DROP TABLE IF EXISTS user_tags; -- Buat tabel data BEGIN; CREATE TABLE IF NOT EXISTS user_tags ( ds timestamptz, tags jsonb ); COMMIT; -
Aktifkan optimasi penyimpanan berorientasi kolom untuk kolom
tags.ALTER TABLE user_tags ALTER COLUMN tags SET (enable_columnar_type = ON); -
Periksa status penyimpanan columnar JSONB.
select * from hologres.hg_column_options where table_name = 'user_tags';Pada hasil berikut, properti options pada baris tags bernilai {enable_columnar_type=on}, yang menunjukkan bahwa konfigurasi berhasil.
schema_name | table_name | column_id | column_name | column_type | notnull | comment | default | options -------------+------------+-----------+-------------+--------------------------+---------+---------+---------+--------------------------- public | user_tags | 1 | ds | timestamp with time zone | f | | | public | user_tags | 2 | tags | jsonb | f | | | {enable_columnar_type=on} (2 rows) -
Impor data.
INSERT INTO user_tags (ds, tags) SELECT '2022-01-01 00:00:00+08' , ('{"id":' || i || ',"first_name" :"Sig", "gender" :"Male"}')::jsonb FROM generate_series(1, 10001) i; -
(Opsional) Paksa flush data.
Setelah data ditulis, sistem melakukan optimasi columnar JSONB selama proses flush data. Untuk melihat efeknya segera, jalankan perintah berikut untuk memaksa flush data.
VACUUM user_tags; -
Jalankan kueri contoh.
Jalankan pernyataan SQL berikut untuk mengkueri
first_namedi manaidbernilai10.SELECT (tags -> 'first_name')::text AS first_name FROM user_tags WHERE (tags -> 'id')::int = 10; -
Periksa rencana eksekusi untuk memverifikasi bahwa kueri menggunakan optimasi columnar.
-- Tampilkan statistik detail. SET hg_experimental_show_execution_statistics_in_explain = ON; -- Lihat rencana eksekusi. EXPLAIN ANALYZE SELECT (tags -> 'first_name')::text AS first_name FROM user_tags WHERE (tags -> 'id')::int = 10;Jika
columnar_access_usedmuncul dalam hasil, optimasi columnar JSONB telah digunakan. -
Untuk kueri pada Langkah 6, Anda juga dapat menetapkan indeks bitmap pada kolom
tagsuntuk meningkatkan efisiensi kueri kesamaan untuk kunci tertentu dengan menggunakan perintah berikut:call set_table_property('user_tags', 'bitmap_columns', 'tags'); -
Periksa rencana eksekusi untuk memverifikasi bahwa indeks bitmap efektif.
-- Lihat rencana eksekusi. EXPLAIN ANALYZE SELECT (tags -> 'first_name')::text AS first_name FROM user_tags WHERE (tags -> 'id')::int = 10;Hasilnya adalah sebagai berikut:
QUERY PLAN Gather (cost=0.00..6.42 rows=3334 width=8) [2:1 id=100002 dop=1 time=7/7/7ms rows=1(1/1/1) mem=584/584/584B open=0/0/0ms get_next=7/7/7ms] -> Local Gather (cost=0.00..6.30 rows=3334 width=8) [id=6 dop=2 time=6/4/3ms rows=1(1/0/0) mem=584/584/584B open=0/0/0ms get_next=6/4/3ms pull_dop=0/0/0] -> Decode (cost=0.00..6.30 rows=3334 width=8) [id=4 dop=2 time=7/5/3ms rows=1(1/0/0) mem=0/0/0B open=7/5/3ms get_next=0/0/0ms] -> Project (cost=0.00..6.20 rows=3334 width=8) [id=3 dop=2 time=7/5/3ms rows=1(1/0/0) mem=2/2/2KB open=7/5/3ms get_next=0/0/0ms] -> Seq Scan on user_tags (cost=0.00..5.18 rows=3334 width=8) Filter: (int4((tags -> 'id'::text)) = 10) [id=2 dop=2 time=7/5/3ms rows=1(1/0/0) mem=260/160/60KB open=7/5/3ms get_next=0/0/0ms scan_rows=10001(8192/5000/1809) bitmap_used=1] ADVICE: [node id : 2] Table user_tags misses bitmap index: ColRef_0012.Jika
bitmap_usedmuncul dalam hasil, indeks bitmap telah digunakan.
Kapan harus menghindari columnar JSONB
Penggunaan columnar JSONB dapat mengurangi penyimpanan dan secara signifikan meningkatkan efisiensi kueri. Namun, fitur ini tidak cocok untuk semua skenario. Kami tidak menyarankan penggunaannya dalam skenario berikut karena dapat berdampak negatif.
Mengembalikan seluruh kolom JSONB
Columnar JSONB Hologres memberikan optimasi yang baik untuk sebagian besar kasus penggunaan. Namun, untuk skenario di mana hasil kueri perlu menyertakan seluruh kolom JSONB, kinerjanya mungkin lebih rendah dibandingkan dengan menyimpan data dalam format JSONB asli. Sebagai contoh, pertimbangkan pernyataan SQL berikut:
-- DDL untuk membuat tabel
CREATE TABLE TBL(key int, json_data jsonb);
SELECT json_data FROM TBL WHERE key = 123;
SELECT * FROM TBL limit 10;
Penurunan kinerja ini terjadi karena lapisan dasar telah mengonversi data JSONB menjadi penyimpanan berorientasi kolom. Oleh karena itu, saat Anda perlu mengkueri data JSON lengkap, sistem harus menyusun ulang data berorientasi kolom kembali ke format JSONB asli:

Langkah ini menghasilkan overhead I/O dan konversi yang signifikan. Jika volume data besar dan jumlah kolom tinggi, proses ini dapat menjadi bottleneck kinerja. Oleh karena itu, kami menyarankan untuk tidak mengaktifkan optimasi berorientasi kolom dalam skenario ini.
Data JSONB yang sangat sparse
Saat Hologres menemui bidang sparse selama mengonversi data JSONB ke format berorientasi kolom, sistem menggabungkan bidang-bidang tersebut ke dalam kolom khusus bernama holo.remaining untuk mencegah ledakan jumlah kolom. Oleh karena itu, jika data JSONB seluruhnya terdiri dari bidang sparse—misalnya, dalam kasus ekstrem di mana setiap bidang hanya muncul sekali—konversi berorientasi kolom tidak akan efektif. Karena semua bidang bersifat sparse, semuanya digabung ke dalam kolom holo.remaining, sehingga tidak terjadi konversi berorientasi kolom yang sebenarnya. Dalam kasus ini, tidak akan ada peningkatan kinerja kueri.
Data JSONB dengan struktur bersarang kompleks
Pada data JSONB berikut, node akar berupa array yang berisi data JSONB non-homogen. Saat ini, ketika Hologres mengonversi data JSONB ke format berorientasi kolom, sistem menurunkan spesifikasi struktur bersarang kompleks seperti ini menjadi satu kolom tunggal. Oleh karena itu, mengaktifkan optimasi columnar JSONB untuk jenis data JSONB ini tidak akan memberikan manfaat signifikan terhadap kinerja kueri.
'[
{"key1": "value1"},
{"key2": 123},
{"key3": 123.01}
]'
Praktik terbaik
Diagnosis kueri lambat
Jika Anda menemukan bahwa kinerja kueri memburuk setelah mengaktifkan columnar JSONB, pertama-tama periksa apakah kueri mengembalikan seluruh kolom JSONB. Jika pernyataan SQL terlalu kompleks, Anda dapat menggunakan perintah EXPLAIN ANALYZE untuk diagnosis. Contoh perintahnya adalah sebagai berikut:
CREATE TABLE TBL(key int, json_data json); -- DDL untuk membuat tabel
ALTER TABLE TBL ALTER COLUMN json_data SET (enable_columnar_type = on);
Explain Analyze SELECT json_data FROM TBL WHERE key = 123;
Hasil EXPLAIN ANALYZE berisi informasi petunjuk. Jika petunjuk tersebut berisi pesan berikut, artinya kueri mengembalikan seluruh kolom JSONB, yang menyebabkan penurunan kinerja:
Column 'json_data' has enabled columnar jsonb, but the query scanned the entire Jsonb value
Sintaks SQL yang lebih efisien
-
Ada beberapa cara untuk mengonversi data bidang JSONB ke format TEXT, tetapi operator
->>memberikan kinerja lebih baik. Sebagai contoh, untuk mendapatkan atribut name dari kolom json_data:-- Kinerja lebih baik SELECT json_data->>'name' FROM tbl; -- Kinerja rata-rata SELECT (json_data->'name')::text FROM tbl; -
Jika bidang JSON menyimpan array TEXT dan Anda perlu memeriksa apakah array tersebut berisi nilai tertentu, kami menyarankan menggunakan sintaks berikut:
SELECT key FROM tbl WHERE jsonb_to_textarray(json_data->'phones') && ARRAY['123456'];
FAQ
Mengapa penggunaan storage space meningkat setelah saya mengaktifkan optimasi berorientasi kolom?
Setelah Anda mengaktifkan optimasi columnar JSONB, nama bidang dari data JSONB asli tidak lagi disimpan. Hanya nilai spesifik untuk setiap bidang yang disimpan. Setelah dikonversi ke format berorientasi kolom, semua data dalam setiap kolom memiliki tipe yang sama, sehingga memungkinkan penyimpanan berorientasi kolom mencapai laju kompresi data yang tinggi. Secara teori, hal ini seharusnya secara signifikan mengurangi ruang penyimpanan data.
Namun, jika bidang dalam data JSONB bersifat sparse dan jumlah kolom meningkat secara signifikan, setiap kolom baru akan menimbulkan overhead penyimpanan tambahan untuk metadata, seperti statistik dan indeks. Selain itu, jika sebagian besar kolom diinferensikan sebagai tipe TEXT, kompresi akan kurang efektif. Oleh karena itu, efisiensi kompresi penyimpanan aktual bergantung pada karakteristik spesifik data Anda, seperti tingkat sparsity, dan kompresi ideal tidak dijamin untuk semua set data.