Materialized view real-time melakukan pra-agregasi dan menyimpan data dari tabel dasar. Mengkueri materialized view mengurangi beban komputasi serta secara signifikan meningkatkan performa kueri. Topik ini menjelaskan cara menggunakan materialized view di Hologres.
Informasi latar belakang
Data dalam materialized view real-time di Hologres tidak perlu direfresh secara manual. Ketika data ditulis ke tabel dasar, perubahan tersebut langsung tercermin dalam kueri terhadap materialized view. Data menjadi terlihat dan teragregasi segera setelah ditulis.
Dalam materialized view real-time, tabel yang menerima penulisan real-time disebut tabel dasar. Semua operasi INSERT, UPDATE, dan DELETE dilakukan pada tabel dasar. Materialized view didefinisikan berdasarkan aturan agregasi pada tabel dasar. Ketika tabel dasar berubah, perubahan tersebut disinkronkan ke materialized view secara real-time. Saat ini, hanya perubahan dari operasi INSERT yang didukung. Dukungan untuk jenis perubahan lainnya akan ditambahkan di masa mendatang.
Batasan
Materialized view real-time tidak mendukung operasi DELETE atau UPDATE pada tabel dasar. Anda harus mengatur properti
appendonlyuntuk tabel dasar. Jika Anda mencoba melakukan operasi DELETE atau UPDATE pada tabel dasar, kesalahanTable XXX is append-onlyakan dikembalikan. Saat menulis data secara real-time menggunakan Flink, propertimutateTypeharus diatur ke InsertOrIgnore.Pembuatan materialized view secara asinkron tidak didukung. Anda harus membuat materialized view bersamaan dengan pembuatan tabel dasar.
Materialized view hanya dapat dibuat untuk satu tabel tunggal. Materialized view tidak mendukung common table expressions (CTE), JOIN antar beberapa tabel, subkueri, atau klausa WHERE, ORDER BY, LIMIT, dan HAVING.
Kunci GROUP BY dan nilai dalam materialized view real-time tidak mendukung ekspresi. Misalnya,
SUM(CASE WHEN COND THEN A ELSE B END),SUM(col1 + col2), danGROUP BY date_trunc('hour', ts)tidak didukung.Maksimal 10 materialized view dapat dibuat untuk setiap tabel dasar. Konsumsi sumber daya meningkat sebanding dengan jumlah materialized view.
Jika materialized view dibuat untuk tabel partisi, kunci GROUP BY materialized view harus mencakup kolom kunci partisi. Materialized view hanya dapat dibuat untuk tabel induk, bukan untuk tabel anaknya.
Jika materialized view dibuat untuk tabel partisi, sintaksis
ATTACH PARTITIONtidak didukung untuk menyambungkan partisi ke tabel induk. Namun, sintaksisCREATE TABLE PARTITION OFdidukung.Operasi
DROP COLUMNtidak didukung pada tabel dasar yang memiliki materialized view.Data dasar materialized view memiliki masa hidup data (TTL) yang sama dengan tabel dasarnya. Jangan mengatur TTL secara manual untuk materialized view. Jika tidak, ketidakkonsistenan data dapat terjadi antara materialized view dan tabel dasar.
Fungsi agregat yang didukung
Saat ini, materialized view mendukung fungsi agregat berikut.
SUM
COUNT
AVG
MIN
MAX
RB_BUILD_CARDINALITY_AGG (Hanya mendukung tipe data BIGINT. Ekstensi roaringbitmap harus dibuat terlebih dahulu.)
Contoh SQL
Buat materialized view real-time
BEGIN; CREATE TABLE base_sales( day text not null, hour int , ts timestamptz, amount float, pk text not null primary key ); CALL SET_TABLE_PROPERTY('base_sales', 'mutate_type', 'appendonly'); -- Setelah materialized view real-time dihapus, Anda dapat menghapus properti appendonly dari tabel dasar dengan menjalankan perintah berikut: --CALL SET_TABLE_PROPERTY('base_sales', 'mutate_type', 'none'); CREATE MATERIALIZED VIEW mv_sales AS SELECT day, hour, avg(amount) AS amount_avg FROM base_sales GROUP BY day, hour; COMMIT; insert into base_sales values(to_char(now(),'YYYYMMDD'),'12',now(),100,'pk1'); insert into base_sales values(to_char(now(),'YYYYMMDD'),'12',now(),200,'pk2'); insert into base_sales values(to_char(now(),'YYYYMMDD'),'12',now(),300,'pk3');Buat materialized view untuk tabel partisi
BEGIN; CREATE TABLE base_sales_p( day text not null, hour int, ts timestamptz, amount float, pk text not null, primary key (day, pk) ) partition by list(day); CALL SET_TABLE_PROPERTY('base_sales_p', 'mutate_type', 'appendonly'); -- day adalah kolom kunci partisi dan harus dimasukkan dalam klausa GROUP BY view. CREATE MATERIALIZED VIEW mv_sales_p AS SELECT day, hour, avg(amount) AS amount_avg FROM base_sales_p GROUP BY day, hour; COMMIT; create table base_sales_20220101 partition of base_sales_p for values in('20220101');Kueri materialized view
SELECT * FROM mv_sales WHERE day = to_char(now(),'YYYYMMDD') AND hour = 12;Hapus materialized view
DROP MATERIALIZED VIEW mv_sales;Menanyakan ruang penyimpanan Tampilan yang di-materialisasi
select pg_relation_size('mv_sales');Kueri total storage space dasar semua materialized view
SELECT schemaname || '.' || matviewname AS mv_full_name, pg_size_pretty(pg_relation_size('"' || schemaname || '"."' || matviewname || '"')) AS mv_size, pg_relation_size('"' || schemaname || '"."' || matviewname || '"') AS order_size FROM pg_matviews ORDER BY order_size DESC;
Gunakan materialized view untuk meningkatkan performa perhitungan UV presisi
Perhitungan unique visitor (UV) presisi merupakan operator dengan kompleksitas komputasi tinggi dan sering menjadi bottleneck performa sistem. Hologres mendukung fungsi agregat RB_BUILD_CARDINALITY_AGG. Dengan menggunakan struktur data RoaringBitmap, Anda dapat melakukan pra-agregasi data BIGINT—yang biasanya merepresentasikan bidang ID bisnis—ke dalam materialized view. Proses ini mencapai deduplikasi real-time untuk statistik UV. Anda dapat membuat materialized view sebagai berikut. Saat ini, hanya agregasi dan deduplikasi untuk bidang BIGINT yang didukung.
-- Perhitungan UV bergantung pada tipe data RoaringBitmap. Ekstensi RoaringBitmap harus dibuat terlebih dahulu.
CREATE EXTENSION if not exists roaringbitmap;
BEGIN;
CREATE TABLE base_sales_r(
day text not null,
hour int ,
ts timestamptz,
amount float,
userid bigint,
pk text not null primary key
);
CALL SET_TABLE_PROPERTY('base_sales_r', 'mutate_type', 'appendonly');
CREATE MATERIALIZED VIEW mv_sales_r AS
SELECT
day,
hour,
avg(amount) AS amount_avg,
rb_build_cardinality_agg(userid) as user_count
FROM base_sales_r
GROUP BY day, hour;
COMMIT;
insert into base_sales_r values(to_char(now(),'YYYYMMDD'),'12',now(),100,1,'pk1');
insert into base_sales_r values(to_char(now(),'YYYYMMDD'),'12',now(),200,2,'pk2');
insert into base_sales_r values(to_char(now(),'YYYYMMDD'),'12',now(),300,3,'pk3');
select user_count as UV from mv_sales_r where day = to_char(now(),'YYYYMMDD') AND hour = 12;Fungsi rb_build_cardinality_agg menghitung jumlah nilai unik. Dalam view mv_sales_r, user_count merepresentasikan jumlah nilai unik dari userid. Anda dapat mengkueri bidang user_count untuk memperoleh jumlah nilai unik tersebut.
Gunakan materialized view untuk mendukung kueri agregat multi-dimensi
Asumsikan Anda telah mendefinisikan materialized view mv_sales dan tabel dasar base_sales berisi data berikut.
Day | Hour | Amount | PK |
20210101 | 12 | 2 | pk1 |
20210101 | 12 | 4 | pk2 |
20210101 | 13 | 6 | pk3 |
Kueri langsung pada sales_mv menghasilkan hasil berikut.
postgres=> select * from mv_sales;
day | hour | amount_avg
-----------+---------+--------------
20210101 | 12 | 3
20210101 | 13 | 6Jika Anda kemudian mencoba mengubah dimensi agregasi materialized view, misalnya dengan melakukan agregasi avg berdasarkan dimensi day, Anda akan memperoleh hasil yang salah. Hal ini karena rata-rata dari rata-rata tidak sama dengan rata-rata keseluruhan.
postgres=> select day, avg(amount_avg) from mv_sales group by day;
day | avg
-----------+--------
20210101 | 4.5Salah satu solusinya adalah membuat materialized view lain yang diagregasi berdasarkan day. Namun, hal ini meningkatkan jumlah materialized view. Hologres menyediakan metode berbasis status agregasi antara yang memungkinkan Anda menggunakan satu materialized view untuk melakukan kueri agregat lintas dimensi berbeda. Contoh berikut menggunakan fungsi AVG. Anda dapat memodifikasi definisi view sebagai berikut.
BEGIN;
CREATE TABLE base_sales(
day text not null,
hour int ,
ts timestamptz,
amount float,
pk text not null primary key
);
CALL SET_TABLE_PROPERTY('base_sales', 'mutate_type', 'appendonly');
CREATE MATERIALIZED VIEW mv_sales_partial AS
SELECT
day,
hour,
avg(amount) as avg,
avg_partial(amount) AS amt_avg_partial
FROM base_sales
GROUP BY day, hour;
COMMIT;Fungsi agregat avg asli didefinisikan ulang sebagai fungsi agregat avg_partial. Kolom amount_avg_partial menyimpan status antara dari hasil agregasi. Saat menjalankan kueri, modifikasi kueri agar menggunakan fungsi avg_final. Hal ini menunjukkan bahwa kueri sedang melakukan agregasi akhir pada status antara tersebut.
postgres=> select day, avg(avg) as avg_avg, avg_final(amt_avg_partial) as real_avg from mv_sales_partial group by day;
day | avg_avg | real_avg
-----------+-----------+----------
20210101 | 4.5 | 4Fungsi agregat yang didukung beserta fungsi agregat parsialnya adalah sebagai berikut.
Fungsi agregat standar | Fungsi agregat parsial | Fungsi agregat akhir |
AVG | AVG_PARTIAL | AVG_FINAL |
RB_BUILD_CARDINALITY_AGG | RB_BUILD_AGG | RB_OR_CARDINALITY_AGG |
Penjelasan TTL
Jika TTL diatur untuk tabel dasar yang memiliki materialized view, Hologres tidak dapat menjamin konsistensi data antara tabel dasar dan materialized view untuk data yang mendekati ambang batas kedaluwarsa TTL. Mengkueri data tersebut dari materialized view menghasilkan perilaku yang tidak terdefinisi. Contoh berikut menggunakan tabel dasar base_sales_table dan materialized view sales_mv.
TTL diatur untuk tabel base_sales_table. Jika data direklaim karena TTL-nya kedaluwarsa, kueri pada tabel dasar menghasilkan hasil berikut.
postgres=> SELECT
day,
hour,
avg(amount) AS amount_avg
FROM base_sales
GROUP BY day, hour;
--Hasil kueri
day | hour | amount_avg
-----------+---------+--------------
20210101 | 12 | 4
20210101 | 13 | 6Namun, karena data yang direklaim telah dimaterialisasi dalam view, kueri pada materialized view mungkin menghasilkan hasil berikut.
postgres=> select * from mv_sales;
--Hasil kueri
day | hour | amount_avg
-----------+---------+--------------
20210101 | 12 | 3
20210101 | 13 | 6Hasil kueri tidak konsisten. Solusi berikut direkomendasikan:
Jangan mengatur TTL untuk tabel detail.
Atur TTL untuk tabel dasar, tetapi pastikan kunci GROUP BY materialized view mencakup bidang berbasis waktu. Saat mengkueri materialized view, hindari mengkueri data yang mendekati ambang batas kedaluwarsa TTL.
Buat tabel dasar sebagai tabel partisi dan jangan atur TTL. Reklaim data dengan menghapus partisi anak.
Praktik terbaik penggunaan materialized view real-time
Saat membuat tabel dasar dan materialized view-nya, atur kunci GROUP BY materialized view agar sama dengan kunci distribusi tabel dasar. Praktik ini dapat meningkatkan rasio kompresi data dan performa kueri.
Saat mendefinisikan materialized view, letakkan kolom yang sering digunakan dalam kondisi filter di awal kunci GROUP BY. Praktik ini mengikuti prinsip pencocokan paling kiri dari kunci pengelompokan.
Routing cerdas untuk materialized view
Anda tidak perlu secara eksplisit menentukan nama materialized view dalam kueri Anda. Sebaliknya, Anda dapat langsung mengkueri tabel dasar. Jika terdapat materialized view yang sesuai, pengoptimal secara cerdas mengarahkan kueri ke materialized view yang paling tepat untuk mempercepat kueri. Pengoptimal memilih materialized view berdasarkan kriteria berikut:
Materialized view berisi semua kolom yang dikueri atau kolom yang nilainya dapat dihitung secara tidak langsung dari kolom yang dikueri.
Kolom GROUP BY materialized view mencakup semua kolom dari klausa GROUP BY kueri asli.
Jika beberapa materialized view memenuhi kriteria di atas, pengoptimal memilih yang memiliki jumlah kolom paling sedikit dalam kunci GROUP BY-nya.
Fungsi agregat yang mendukung routing cerdas adalah SUM, COUNT, MIN, dan MAX.