All Products
Search
Document Center

Hologres:Optimalkan kinerja kueri tabel internal

Last Updated:Jul 16, 2026

Pelajari cara menyetel kueri tabel internal Hologres dengan memelihara statistik, mengonfigurasi shard, mengoptimalkan penggabungan tabel (join) dan agregasi, serta merancang skema tabel yang efisien.

Panduan keputusan cepat

Gejala

Kemungkinan penyebab

Aksi yang direkomendasikan

Join lambat pada tabel internal berukuran besar

Statistik usang

Jalankan ANALYZE pada semua tabel yang terlibat dalam join

Kueri memindai terlalu banyak baris untuk filter rentang atau kesamaan

Tidak ada clustering key, kolom bitmap, atau segment key

Tambahkan clustering_key untuk filter rentang, bitmap_columns untuk filter kesamaan, atau segment_key untuk rentang berbasis waktu

Latensi tinggi untuk kueri titik (point queries)

Tipe penyimpanan tidak sesuai atau tidak ada primary key/indeks

Gunakan penyimpanan row atau hybrid dan definisikan primary key serta indeks yang sesuai

Agregasi COUNT DISTINCT lambat

Deduplikasi eksak yang intensif sumber daya

Gunakan APPROX_COUNT_DISTINCT atau UNIQ, dan pertimbangkan menggunakan distinct key sebagai distribution key

Agregasi GROUP BY lambat

Redistribusi data dan data skew pada kunci GROUP BY

Tetapkan kunci GROUP BY sebagai distribution key jika memungkinkan dan perbaiki data skew

Memelihara statistik

Statistik (misalnya, distribusi data, jumlah baris, kolom) membantu pengoptimal memilih rencana eksekusi yang efisien. Statistik yang usang dapat menyebabkan pemilihan urutan join yang buruk dan error OOM.

Periksa apakah statistik terkini

Jalankan EXPLAIN pada kueri Anda dan periksa estimasi rows untuk setiap tabel.

Jika tabel besar menunjukkan rows=1000 (nilai default), statistik tersebut sudah usang.

Perbarui statistik

Jalankan ANALYZE pada tabel dengan statistik usang:

analyze <tablename>;

Identifikasi kapan harus memperbarui statistik

Jalankan analyze <tablename> saat:

  • Setelah mengimpor data.

  • Setelah beberapa operasi INSERT, UPDATE, atau DELETE.

  • Untuk tabel internal maupun tabel eksternal.

  • Pada tabel induk untuk tabel partisi.

Jika Anda mengalami error OOM selama join atau kueri lambat, jalankan analyze <tablename> sebelum mengimpor data.

Mengonfigurasi jumlah shard

Jumlah shard menentukan paralelisme kueri. Terlalu sedikit shard membatasi paralelisme; terlalu banyak meningkatkan overhead startup.

Pahami jumlah shard default

Hologres menetapkan jumlah shard default berdasarkan spesifikasi instans, kira-kira sama dengan jumlah CU kueri yang tersedia. Setelah penskalaan, database yang sudah ada mempertahankan jumlah shard aslinya—hanya database baru yang menggunakan nilai default yang diperbarui.

Tentukan kapan harus menyesuaikan jumlah shard

  • Setelah penskalaan naik 5x atau lebih: Buat Table Group baru dengan jumlah shard yang lebih besar.

  • Untuk workload bisnis baru: Buat Table Group baru dengan jumlah shard yang sesuai.

  • Saat mengalami masalah paralelisme: Periksa apakah total shard melebihi nilai default yang direkomendasikan.

Catatan

Total shard di seluruh Table Group sebaiknya tidak melebihi jumlah shard default instans agar pemanfaatan CPU optimal.

Mengoptimalkan kueri JOIN

Gunakan metode berikut untuk meningkatkan kinerja join.

Perbarui statistik untuk kueri join

Seperti disebutkan dalam Memelihara statistik, statistik yang usang dapat menyebabkan tabel yang lebih besar membuat hash table, sehingga mengurangi efisiensi join. Jalankan ANALYZE untuk memperbarui statistik tabel.

Pilih distribution key untuk join lokal

Distribution key menentukan bagaimana data didistribusikan ke seluruh shard. Pemilihan yang tepat memungkinkan join lokal dan mengurangi pengacakan data (data shuffling).

Prinsip pemilihan distribution key:

  • Gunakan kolom join sebagai distribution key.

  • Gunakan kolom dalam klausa GROUP BY yang sering digunakan.

  • Pilih kolom dengan distribusi data yang merata dan diskret.

Contoh: Saat melakukan join tabel secara rutin pada kolom tertentu, tetapkan kolom tersebut sebagai distribution key untuk kedua tabel:

-- Buat tabel dengan distribution key yang cocok
BEGIN;
CREATE TABLE orders (order_id INT, customer_id INT, amount DECIMAL);
CALL set_table_property('orders', 'distribution_key', 'customer_id');
COMMIT;

BEGIN;
CREATE TABLE customers (id INT, name TEXT);
CALL set_table_property('customers', 'distribution_key', 'id');
COMMIT;

Dengan distribution key yang benar, rencana eksekusi tidak menampilkan operator Redistribute Motion, yang mengonfirmasi join lokal.

Gunakan Runtime Filter dalam join

Sejak V2.0, Hologres secara otomatis menerapkan Percepat join multi-tabel dengan runtime filter untuk join tabel besar-kecil, sehingga mengurangi data yang dipindai tanpa konfigurasi manual.

Menyetel algoritma urutan join

Untuk kueri yang menggabungkan banyak tabel, pengoptimal mungkin memerlukan waktu terlalu lama untuk menemukan urutan join optimal. Sesuaikan algoritma sesuai kebutuhan:

set optimizer_join_order = '<value>'; 

Algoritma

Kasus penggunaan

Trade-off

exhaustive2

Default untuk sebagian besar kueri

Rencana terbaik, biaya optimasi tertinggi

greedy

Lebih dari 10 tabel

Optimasi lebih cepat, rencana berpotensi suboptimal

query

SQL sederhana dengan urutan jelas

Dieksekusi sesuai urutan SQL, biaya optimasi terendah

Mengoptimalkan operator Motion dalam join

Hologres menggunakan operator Motion untuk mendistribusikan ulang data antar shard:

Jenis Motion

Deskripsi

Redistribute Motion

Mengacak data berdasarkan hash atau acak

Broadcast Motion

Menyalin data ke semua shard.

Gather Motion

Mengumpulkan data ke satu shard.

Forward Motion

Memindahkan data antara sumber eksternal dan Hologres untuk kueri federasi.

Periksa rencana eksekusi untuk operator Motion yang mahal dan sesuaikan desain tabel:

  • Operator Motion yang memakan waktu: Rancang ulang distribusi.

  • Karakteristik Motion tidak efisien akibat statistik usang: Segarkan statistik dengan analyze.

  • Membroadcast tabel kecil: Kurangi jumlah shard untuk mengoptimalkan efisiensi Broadcast Motion.

Mengoptimalkan agregasi

Mengoptimalkan COUNT DISTINCT

  • Ganti COUNT DISTINCT eksak (intensif sumber daya) dengan APPROX_COUNT_DISTINCT (lebih cepat, tingkat error 0,1% hingga 1%) bila variasi kecil dapat diterima.

  • Ganti COUNT DISTINCT dengan UNIQ (V1.3+).

  • Tetapkan distribution key yang sesuai

    Gunakan kunci COUNT DISTINCT sebagai distribution key untuk menghindari pengacakan data antar shard.

  • Upgrade ke V2.1+ untuk optimasi bawaan

    V2.1+ mencakup optimasi bawaan untuk skenario COUNT DISTINCT termasuk satu atau lebih COUNT DISTINCT, data skew, dan kueri tanpa GROUP BY.

Paksa agregasi multi-tahap

Agregasi multi-tahap mengurangi transfer data dengan melakukan agregasi parsial di setiap shard terlebih dahulu:

set optimizer_force_multistage_agg = on;

Mengoptimalkan beberapa fungsi agregat pada kolom yang sama

Sejak V4.0, Hologres secara otomatis mendeduplikasi fungsi agregat identik pada kolom yang sama, sehingga mengurangi komputasi. Upgrade ke V4.0+ untuk menggunakan optimasi ini.

Contoh:

-- Buat tabel uji.
CREATE TABLE tbl(x int4, y int4);

-- Masukkan data uji.
INSERT INTO tbl VALUES (1,2), (null,200), (1000,null), (10000,20000);

-- Kueri data
SELECT
    sum(x + 1),
    sum(x + 2),
    sum(x - 3),
    sum(x - 4)
FROM
    tbl;

Rencana kueri menunjukkan x adalah satu-satunya kunci grup.

Untuk menonaktifkan:

-- Nonaktifkan pada tingkat session.
SET hg_experimental_remove_related_group_by_key = off; 

-- Nonaktifkan pada tingkat DB.
ALTER DATABASE <database_name> SET hg_experimental_remove_related_group_by_key = off; 

Mengoptimalkan skema tabel dan indeks

Pilih format penyimpanan

Hologres mendukung penyimpanan row, column, dan hybrid. Pilih berdasarkan workload Anda:

Format penyimpanan

Paling cocok untuk

Trade-off

Row store

Kueri titik berdasarkan primary key, UPDATE/DELETE yang sering

Kinerja pemindaian rentang dan agregasi buruk

Column store

Analitik, kueri multi-kolom, agregasi

UPDATE/DELETE dan kueri titik lebih lambat

Hybrid row-columnar store

Workload campuran

Overhead penyimpanan lebih tinggi

Pilih tipe data

  • Gunakan tipe lebih kecil bila memungkinkan (INT alih-alih BIGINT)

  • Tentukan presisi untuk tipe DECIMAL/NUMERIC.

  • Hindari FLOAT atau DOUBLE untuk kolom GROUP BY.

  • Gunakan TEXT untuk fleksibilitas. Minimalkan N saat menggunakan VARCHAR(N) atau CHAR(N).

  • Gunakan TIMESTAMPTZ dan DATE alih-alih TEXT untuk tanggal.

  • Gunakan tipe data konsisten dalam kondisi join untuk menghindari konversi implisit

Rancang primary key

Primary key menjamin keunikan data. Pilih metode deduplikasi saat mengimpor:

  • ignore: Abaikan data baru.

  • update: Timpa data lama.

Primary key yang tepat meningkatkan rencana eksekusi, terutama untuk kueri GROUP BY.

Dalam mode columnar store, primary key memperlambat penulisan—throughput biasanya 3x lebih tinggi tanpa primary key.

Gunakan tabel partisi

Hologres mendukung partisi tingkat tunggal. Partisi yang tepat mempercepat kueri, tetapi terlalu banyak partisi menghasilkan file kecil dan menurunkan kinerja.

Catatan

Buat partisi harian untuk data inkremental guna mengisolasi penyimpanan dan akses.

Skenario penerapan:

  • DROP atau TRUNCATE seluruh partisi untuk kinerja lebih baik daripada DELETE dan tidak berdampak pada partisi lain.

  • Isolasi pemindaian hanya ke partisi atau tabel anak tertentu.

  • Gunakan tabel partisi untuk impor real-time periodik. Misalnya, gunakan tanggal sebagai kunci partisi. Contoh pernyataan:

  • begin;
    create table insert_partition(c1 bigint not null, c2 boolean, c3 float not null, c4 text, c5 timestamptz not null) partition by list(c4);
    call set_table_property('insert_partition', 'orientation', 'column');
    commit;
    create table insert_partition_child1 partition of insert_partition for values in('20190707');
    create table insert_partition_child2 partition of insert_partition for values in('20190708');
    create table insert_partition_child3 partition of insert_partition for values in('20190709');
    
    select * from insert_partition where c4 >= '20190708';
    select * from insert_partition_child3;

Pilih indeks yang tepat

Hologres menyediakan beberapa jenis indeks. Definisikan indeks saat membuat tabel:

Jenis

Tujuan

Contoh kueri

clustering_key

Kueri rentang dan penyaringan

WHERE created_at > '2024-01-01'

bitmap_columns

Kueri kesamaan

WHERE status = 'active'

segment_key (juga dikenal sebagai event_time_column)

Penyaringan berbasis waktu (tingkat file)

Penyaringan cepat tingkat file sebelum indeks bitmap atau clustering. Mengikuti prinsip pencocokan prefiks paling kiri (biasanya 1 kolom). Gunakan timestamp non-kosong pertama sebagai segment_key.

WHERE event_time > '2020-01-01';

Catatan:

  • Clustering key dan segment key mengikuti prinsip pencocokan prefiks paling kiri.

  • Indeks bitmap mendukung kueri AND/OR pada beberapa kolom.

  • Gunakan segment_key terlebih dahulu untuk penyaringan berbasis waktu, lalu bitmap_columns untuk kesamaan atau clustering_key untuk kueri rentang.

Contoh:

BEGIN;
CREATE TABLE events (
    event_id INT NOT NULL,
    user_id INT NOT NULL,
    event_time TIMESTAMPTZ NOT NULL,
    event_type TEXT
);
CALL set_table_property('events', 'clustering_key', 'event_time');
CALL set_table_property('events', 'segment_key', 'event_time');
CALL set_table_property('events', 'bitmap_columns', 'user_id,event_type');
COMMIT;
Catatan

bitmap_columns dapat ditambahkan setelah pembuatan tabel. clustering_key dan segment_key harus ditentukan saat pembuatan.

Verifikasi penggunaan indeks dalam kueri dengan menjalankan EXPLAIN:

EXPLAIN SELECT * FROM events WHERE event_time > '2026-01-01';

Nonaktifkan dictionary encoding untuk kolom karakter

Dictionary encoding mempercepat perbandingan string tetapi menambahkan overhead encode/decode. Nonaktifkan untuk kolom di mana biaya perbandingan rendah:

BEGIN;
CREATE TABLE logs (id INT, message TEXT);
CALL set_table_property('logs', 'dictionary_encoding_columns', '');
COMMIT;

Mengoptimalkan pernyataan SQL

Hindari SQL eksternal (Postgres) seperti NOT IN

Hologres menggunakan HQE (Hologres Query Engine) untuk kinerja terbaik. Operator yang tidak didukung akan fallback ke PQE (Postgres Query Engine), yang lebih lambat.

Memeriksa fallback ke PQE dalam rencana eksekusi:

EXPLAIN SELECT * FROM orders WHERE id NOT IN (SELECT id FROM cancelled_orders);

Jika Anda melihat External SQL (Postgres), tulis ulang kueri:

Tidak didukung HQE

Tulis ulang menjadi

Contoh

Catatan

NOT IN

NOT EXISTS

select * from tmp where not exists (select a from tmp1 where a = tmp.a);

N/A.

regexp_split_to_table

unnest(string_to_array)

select name,unnest(string_to_array(age,',')) from demo;

regexp_split_to_table mendukung ekspresi reguler.

Mulai Hologres V2.0.4, HQE mendukung regexp_split_to_table. Aktifkan GUC dengan perintah berikut: set hg_experimental_enable_hqe_table_function = on;

substring

extract(hour from to_timestamp(c1, 'YYYYMMDD HH24:MI:SS'))

select cast(substring(c1, 13, 2) as int) AS hour from t2;

Tulis ulang sebagai:

select extract(hour from to_timestamp(c1, 'YYYYMMDD HH24:MI:SS')) from t2;

Beberapa versi V0.10 dan sebelumnya tidak mendukung substring. Mulai V1.3, HQE mendukung input non-regex untuk substring.

regexp_replace

replace

select regexp_replace(c1::text,'-','0') from t2;

Tulis ulang sebagai:

select replace(c1::text,'-','') from t2;

replace tidak mendukung ekspresi reguler.

at time zone 'utc'

Hapus at time zone 'utc'

select date_trunc('day',to_timestamp(c1, 'YYYYMMDD HH24:MI:SS')  at time zone 'utc') from t2

Tulis ulang sebagai:

select date_trunc('day',to_timestamp(c1, 'YYYYMMDD HH24:MI:SS') ) from t2;

N/A.

CAST(text AS timestamp)

to_timestamp

select cast(c1 as timestamp) from t2;

Tulis ulang sebagai:

select to_timestamp(c1, 'yyyyMMdd hh24:mi:ss') from t2;

Didukung oleh HQE mulai Hologres V2.0.

timestamp::text

to_char

select c1::text from t2;

Tulis ulang sebagai:

select to_char(c1, 'yyyyMMdd hh24:mi:ss') from t2;

Didukung oleh HQE mulai Hologres V2.0.

Hindari kueri LIKE fuzzy

Hindari pencarian fuzzy seperti operasi LIKE karena tidak menggunakan indeks.

Mengoptimalkan kueri ORDER BY LIMIT

Sejak V1.3, Hologres mendukung Merge Sort untuk kueri ORDER BY ... LIMIT, sehingga menghilangkan operasi sort berlebihan.

Mengoptimalkan kueri GROUP BY

Tetapkan kolom GROUP BY sebagai distribution key untuk mengurangi redistribusi data.

-- Jika data didistribusikan berdasarkan nilai pada kolom a, redistribusi data saat runtime berkurang, dan kemampuan komputasi paralel shard dimanfaatkan sepenuhnya.
select a, count(1) from t1 group by a; 

Sejak V4.0, Hologres secara otomatis menulis ulang kolom GROUP BY terkait untuk mengurangi penggabungan (kedalaman pencarian maks: 5 lapis). Klausa seperti GROUP BY COL_A, ((COL_A + 1)), ((COL_A + 2)) ditulis ulang menjadi GROUP BY COL_A. Contoh:

CREATE TABLE tbl (
    a int,
    b int,
    c int
);

-- Kueri
SELECT
    a,
    a + 1 as a1,
    a + 2 as a2,
    sum(b)
FROM tbl
GROUP BY
    a,
    a1,
    a2;

Rencana eksekusi mengonfirmasi penulisan ulang—klausa GROUP BY hanya berisi kolom a.

QUERY PLAN
Gather  (cost=0.00..5.00 rows=1 width=20)
  -> Project  (cost=0.00..5.00 rows=1 width=20)
    -> HashAggregate  (cost=0.00..5.00 rows=1 width=12)
          Group Key: a
        -> Redistribution  (cost=0.00..5.00 rows=1 width=8)
              Hash Key: a
            -> Local Gather  (cost=0.00..5.00 rows=1 width=8)
              -> Seq Scan on tbl  (cost=0.00..5.00 rows=1 width=8)
Query Queue: init_warehouse.default_queue
Optimizer: HQO version 4.0.0

Untuk menonaktifkan:

-- Nonaktifkan fitur ini pada tingkat session.
SET hg_experimental_remove_related_group_by_key = off; 

-- Nonaktifkan fitur ini pada tingkat database.
ALTER DATABASE <database_name> SET hg_experimental_remove_related_group_by_key = off; 

Aktifkan penggunaan kembali CTE

Saat CTE dirujuk beberapa kali, aktifkan reuse CTE untuk menghindari komputasi ulang (V1.3+):

SET optimizer_cte_inlining=off;
Catatan
  • Reuse CTE secara default dinonaktifkan. Aktifkan secara manual melalui GUC.

  • Reuse CTE bergantung pada Spill pada tahap Shuffle. Volume data besar dapat memengaruhi kinerja akibat laju konsumsi yang berbeda-beda.

Mengoptimalkan analisis Top-N

  • Dalam skenario OLAP, mengambil N record teratas dalam suatu grup merupakan kebutuhan umum. Misalnya, kueri SQL berikut mengambil dua record teratas dari tabel t dalam setiap partisi b, diurutkan berdasarkan a:

    CREATE TABLE t (
      a int,
      b int
    );
    
    INSERT INTO t VALUES (2, 1), (3, 1), (4, 1), (5, 2), (6, 2);
    
    SELECT
        *
    FROM (
      SELECT
      a,
      b,
      row_number() OVER (PARTITION BY b ORDER BY a) AS rn
      FROM
      t) t1
    WHERE
        rn <= 2;

    Hasil eksekusi adalah sebagai berikut:

    a	b	rn
    5	2	1
    6	2	2
    2	1	1
    3	1	2
  • Mulai Hologres V4.1, operator Partition Sort mendorong klausa LIMIT ke dalam Partition, sehingga menyaring data lebih awal selama pengurutan. Ini mengurangi memori untuk fungsi jendela seperti row_number dan rank dalam skenario Top-N, sehingga menurunkan risiko OOM. Diaktifkan secara default. Untuk menonaktifkan:

    -- Nonaktifkan fitur ini pada tingkat session.
    SET hg_experimental_enable_hash_partitioned_sort_v2 = off; 
    
    -- Nonaktifkan fitur ini pada tingkat database.
    ALTER DATABASE <database_name> SET hg_experimental_enable_hash_partitioned_sort_v2 = off; 

Menangani data skew

Distribusi data yang tidak merata memperlambat kueri. Periksa jumlah baris per shard untuk mendeteksi skew:

-- hg_shard_id adalah kolom tersembunyi bawaan di setiap tabel yang menggambarkan shard tempat baris data terkait berada.
SELECT hg_shard_id, count(1) FROM t1 GROUP BY hg_shard_id;

Jika beberapa shard memiliki jumlah baris jauh lebih banyak daripada yang lain:

  • Ubah distribution_key menjadi kolom dengan distribusi data yang merata.

    Penting

    Mengubah distribution key memerlukan pembuatan ulang tabel dan pengimporan ulang data.

  • Jika data memang skew secara inheren, optimalkan dari perspektif bisnis

Nonaktifkan caching hasil untuk pengujian

Hologres secara default menyimpan cache hasil kueri. Nonaktifkan caching saat melakukan benchmark kinerja:

set hg_experimental_enable_result_cache = off;

Informasi terkait