Materialized view

Menyimpan hasil query secara fisik dan menyegarkannya dengan REFRESH.

Daftar isi

Topik ini membahas materialized view, yaitu view yang hasilnya disimpan secara fisik, sehingga pembacaannya tidak menjalankan query sumbernya. Perbedaan ini membalik pertukarannya, yaitu pembacaan yang sangat cepat dibayar dengan data yang menua sampai disegarkan kembali melalui REFRESH.

Blok penyiapan dataset#

bash
# siapkan ulang tabel dan data contoh untuk topik ini
PGOPTIONS='-c client_min_messages=warning' psql -q -U postgres -d perpustakaan <<'SQL'
DROP TABLE IF EXISTS peminjaman, buku, anggota, kategori, rekap_kategori CASCADE;
CREATE TABLE kategori (id SERIAL PRIMARY KEY, nama TEXT NOT NULL UNIQUE);
CREATE TABLE anggota (id SERIAL PRIMARY KEY, nama TEXT NOT NULL, email TEXT UNIQUE, bergabung DATE NOT NULL, aktif BOOLEAN NOT NULL DEFAULT TRUE);
CREATE TABLE buku (id SERIAL PRIMARY KEY, judul TEXT NOT NULL, penulis TEXT NOT NULL, tahun INTEGER NOT NULL, kategori_id INTEGER REFERENCES kategori(id));
CREATE TABLE peminjaman (id SERIAL PRIMARY KEY, anggota_id INTEGER NOT NULL REFERENCES anggota(id), buku_id INTEGER NOT NULL REFERENCES buku(id), tanggal_pinjam DATE NOT NULL, tanggal_kembali DATE);
INSERT INTO kategori (nama) VALUES ('Pemrograman'), ('Sains'), ('Sejarah'), ('Fiksi'), ('Statistika');
INSERT INTO anggota (nama, email, bergabung, aktif) VALUES ('Ali Rahman', '[email protected]', '2024-01-15', TRUE), ('Budi Santoso', '[email protected]', '2024-03-02', TRUE), ('Citra Kirana', '[email protected]', '2024-05-20', FALSE), ('Dewi Lestari', '[email protected]', '2024-08-11', TRUE), ('Eka Pratama', NULL, '2025-01-30', TRUE);
INSERT INTO buku (judul, penulis, tahun, kategori_id) VALUES ('Dasar Basis Data', 'Sari Wulandari', 2021, 1), ('Jaringan Komputer', 'Ahmad Fauzi', 2019, 1), ('Fisika untuk Pemula', 'Rina Marlina', 2020, 2), ('Kimia Organik', 'Rina Marlina', 2022, 2), ('Sejarah Nusantara', 'Bambang Wijaya', 2018, 3), ('Cerita Kota Lama', 'Nur Aisyah', 2023, 4), ('Statistika Terapan', 'Sari Wulandari', 2022, 5), ('Algoritma dan Struktur Data', 'Ahmad Fauzi', 2021, 1);
INSERT INTO peminjaman (anggota_id, buku_id, tanggal_pinjam, tanggal_kembali) VALUES (1, 1, '2025-03-01', '2025-03-15'), (1, 7, '2025-03-05', '2025-03-20'), (2, 3, '2025-03-10', NULL), (3, 5, '2025-02-20', '2025-03-01'), (2, 1, '2025-04-02', NULL), (4, 6, '2025-04-07', NULL), (5, 8, '2025-04-09', '2025-04-25'), (4, 2, '2025-05-01', NULL);
SQL

Hasil yang tersimpan secara fisik#

CREATE MATERIALIZED VIEW menjalankan query sumbernya sekali dan menyimpan hasilnya, dan pembacaan berikutnya membaca hasil tersimpan itu. Blok berikut menyimpan rekap per kategori, membacanya, lalu menambah data dan melihat bahwa rekapnya belum berubah.

bash
# rekap tersimpan yang belum mengikuti data baru
psql -U postgres -d perpustakaan <<'SQL'
CREATE MATERIALIZED VIEW rekap_kategori AS
SELECT k.nama AS kategori, COUNT(p.id) AS pinjaman
FROM kategori k
LEFT JOIN buku b ON b.kategori_id = k.id
LEFT JOIN peminjaman p ON p.buku_id = b.id
GROUP BY k.nama;
SELECT kategori, pinjaman FROM rekap_kategori ORDER BY pinjaman DESC;
INSERT INTO peminjaman (anggota_id, buku_id, tanggal_pinjam) VALUES (1, 2, '2025-05-10');
SELECT pinjaman FROM rekap_kategori WHERE kategori = 'Pemrograman';
SQL
text Keluaran
SELECT 5
  kategori   | pinjaman
-------------+----------
 Pemrograman |        4
 Statistika  |        1
 Fiksi       |        1
 Sejarah     |        1
 Sains       |        1
(5 rows)

INSERT 0 1
 pinjaman
----------
        4
(1 row)

Pembacaan pertama menampilkan rekap yang benar pada saat pembuatannya, sedangkan pembacaan kedua tetap menunjukkan angka lama meskipun peminjaman baru sudah masuk. Jeda inilah watak materialized view, dan keputusan memakainya selalu menyertakan jawaban atas pertanyaan seberapa segar data yang masih dapat diterima.

Menyegarkan dengan REFRESH#

REFRESH MATERIALIZED VIEW menjalankan ulang query sumbernya dan menimpa hasil tersimpannya, dan opsinya menentukan perilakunya saat disegarkan. Blok berikut menyegarkan rekap lalu melihat angka barunya.

bash
# segarkan dan baca ulang rekap
psql -U postgres -d perpustakaan -c "REFRESH MATERIALIZED VIEW rekap_kategori;"
psql -U postgres -d perpustakaan -c "SELECT kategori, pinjaman FROM rekap_kategori ORDER BY pinjaman DESC LIMIT 2;"
psql -U postgres -d perpustakaan -c "DROP MATERIALIZED VIEW rekap_kategori;"
text Keluaran
REFRESH MATERIALIZED VIEW
  kategori   | pinjaman
-------------+----------
 Pemrograman |        5
 Fiksi       |        1
(2 rows)

DROP MATERIALIZED VIEW

Angka Pemrograman naik menjadi enam setelah penyegaran, dan seluruh isi view diganti sekaligus. Bentuk bawaannya mengunci pembacaan selama penyegaran berlangsung, sedangkan REFRESH MATERIALIZED VIEW CONCURRENTLY menyegarkan tanpa memblokir pembaca, dengan syarat view memiliki index unik yang menopangnya, kebutuhan yang dinyatakan pada dokumentasi resmi.

Strategi penyegaran#

Penyegaran tidak terjadi sendirinya, sehingga setiap materialized view menyertakan strategi yang menyebut siapa dan kapan menyegarkannya. Tiga pola yang umum adalah penyegaran berkala melalui penjadwal eksternal, penyegaran yang dipicu peristiwa melalui trigger atau pekerjaan pemuatan, dan penyegaran manual pada laporan yang jarang dibaca.

Pemilihan query sumbernya juga bagian dari strategi, karena materialized view paling cocok untuk agregasi yang mahal dibaca sering, sedangkan query yang murah tidak sepadan dengan biaya penyimpanan dan penyegarannya. Index pada materialized view dibuat seperti pada tabel biasa dan tetap hidup antar penyegaran, dengan catatan CONCURRENTLY menuntut satu index unik di antaranya.

Kesalahan umum#

Kesalahan pertama adalah membaca materialized view seolah datanya langsung, padahal usianya bergantung pada penyegaran terakhir, dan kebiasaan yang menyelamatkan mencatat sumber serta jadwal penyegarannya pada namanya atau dokumentasinya. Kesalahan kedua adalah menyegarkan tanpa CONCURRENTLY pada view yang dibaca terus-menerus, sehingga pembaca menunggu atau gagal selama penyegarannya.

Kesalahan ketiga adalah memakai materialized view untuk data yang menuntut kekinian, misalnya saldo yang dibaca saat transaksi, karena jeda penyegarannya melanggar makna datanya. Kesalahan keempat adalah lupa membuat index unik sebelum memakai CONCURRENTLY, yang ditolak server dengan pesan yang jelas, dan perencanaan index dilakukan sejak pembuatan view-nya.

Usia isi materialized view dapat diamati tanpa membaca isinya, dan katalog sistem menyimpan nama seluruh materialized view beserta definisi sumbernya untuk keperluan audit. Kebiasaan operasional yang menyertai adalah mencatat waktu penyegaran terakhir pada tabel khusus yang diisi oleh langkah penyegarannya, sehingga laporan yang membaca view dapat menyertakan tanda usia datanya. Praktik kecil ini menghindarkan laporan dan pembacanya dari selisih harapan yang sulit dilacak.

Ringkasan#

  • CREATE MATERIALIZED VIEW menyimpan hasil query secara fisik, dan pembacaannya tidak menjalankan query sumber.
  • Hasilnya menua sampai REFRESH MATERIALIZED VIEW menjalankan ulang sumbernya dan menimpa isi view.
  • CONCURRENTLY menyegarkan tanpa memblokir pembaca, dengan syarat index unik yang menopangnya.
  • Setiap materialized view menyertakan strategi penyegaran yang nyata, karena segarnya data bergantung padanya.

Referensi#