Foto oleh panumas nikhomkhai via Pexels

VIEW adalah objek database yang menyimpan definisi query SELECT secara permanen dengan nama tertentu, sehingga bisa dipanggil berulang kali seperti memanggil tabel biasa tanpa perlu menulis ulang query yang sama berkali-kali di berbagai tempat.

Berbeda dengan tabel fisik, VIEW tidak menyimpan data secara langsung (kecuali indexed view); setiap kali VIEW dipanggil, SQL Server akan menjalankan ulang query SELECT yang menjadi definisinya terhadap data terbaru pada tabel sumber. Ini membuat VIEW selalu menampilkan data terkini tanpa risiko data basi.

Artikel ini membahas cara membuat VIEW, mengubahnya, serta pertimbangan penting seperti keterbatasan VIEW untuk operasi tulis dan dampaknya terhadap performa jika dipakai sembarangan dalam query yang sudah kompleks.

Membuat VIEW Dasar dengan CREATE VIEW

CREATE VIEW menyimpan definisi query secara permanen

CREATE VIEW vw_PelangganAktif AS SELECT c.CustomerID, c.CustomerName, COUNT(o.OrderID) AS JumlahPesanan FROM Customers c JOIN Orders o ON o.CustomerID = c.CustomerID GROUP BY c.CustomerID, c.CustomerName; -- Setelah dibuat, panggil seperti tabel biasa: SELECT * FROM vw_PelangganAktif WHERE JumlahPesanan > 3;
Setelah VIEW dibuat, pengguna bisa memperlakukannya persis seperti tabel biasa: melakukan SELECT dengan WHERE, JOIN dengan tabel lain, bahkan membuat VIEW baru yang memakai VIEW ini sebagai sumbernya. Ini membuat VIEW sangat berguna untuk menyembunyikan kompleksitas query JOIN atau agregasi yang panjang dari pengguna akhir.

Mengubah Definisi VIEW dengan ALTER VIEW

ALTER VIEW mengubah definisi tanpa menghapus objeknya

ALTER VIEW vw_PelangganAktif AS SELECT c.CustomerID, c.CustomerName, COUNT(o.OrderID) AS JumlahPesanan, MAX(o.OrderDate) AS PesananTerakhir FROM Customers c JOIN Orders o ON o.CustomerID = c.CustomerID GROUP BY c.CustomerID, c.CustomerName; -- Expected: VIEW sekarang juga menampilkan -- kolom PesananTerakhir tanpa perlu DROP dulu
ALTER VIEW dipakai untuk mengubah definisi query sebuah VIEW yang sudah ada tanpa perlu menghapusnya terlebih dahulu, sehingga izin akses (permission) yang sudah diberikan ke VIEW tersebut tetap terjaga. Ini berbeda dengan DROP lalu CREATE ulang, yang akan menghapus seluruh permission yang pernah diberikan ke objek tersebut.

Keterbatasan VIEW untuk Operasi INSERT dan UPDATE

Updatable view terbatas pada struktur tertentu

-- VIEW sederhana dari satu tabel masih bisa di-UPDATE UPDATE vw_PelangganAktif SET CustomerName = 'Budi Baru' WHERE CustomerID = 5; -- Namun VIEW dengan JOIN atau GROUP BY -- umumnya TIDAK bisa langsung di-UPDATE atau di-INSERT
VIEW yang didefinisikan dari satu tabel tanpa agregasi masih bisa menerima operasi INSERT dan UPDATE yang akan diteruskan ke tabel aslinya, namun begitu VIEW melibatkan JOIN, GROUP BY, DISTINCT, atau fungsi agregat, SQL Server akan menolak operasi tulis tersebut karena tidak jelas baris tabel sumber mana yang harus diubah.

Indexed View untuk Mempercepat Query Berat

Indexed view menyimpan data secara fisik lewat clustered index

CREATE VIEW vw_TotalPenjualanHarian WITH SCHEMABINDING AS SELECT CAST(OrderDate AS DATE) AS Tanggal, SUM(TotalAmount) AS Total, COUNT_BIG(*) AS Jumlah FROM dbo.Orders GROUP BY CAST(OrderDate AS DATE); GO CREATE UNIQUE CLUSTERED INDEX IX_vw_TotalPenjualanHarian ON vw_TotalPenjualanHarian (Tanggal);
Indexed view adalah VIEW khusus yang diberi clustered index, sehingga hasilnya benar-benar disimpan secara fisik di disk layaknya tabel, bukan dihitung ulang setiap kali dipanggil. Pendekatan ini membutuhkan WITH SCHEMABINDING dan sejumlah syarat ketat lainnya, namun bisa mempercepat query agregat berat secara signifikan karena hasilnya sudah tersedia.

Indexed View dan Batasannya di SQL Server

Membuat indexed view dengan SCHEMABINDING dan clustered index

-- Membuat view dengan SCHEMABINDING agar bisa diberi index CREATE VIEW dbo.vw_SalesSummary WITH SCHEMABINDING AS SELECT ProductID, COUNT_BIG(*) AS JumlahTransaksi, SUM(Quantity) AS TotalQuantity FROM dbo.OrderDetails GROUP BY ProductID; GO -- Clustered index pada view inilah yang membuatnya jadi indexed view CREATE UNIQUE CLUSTERED INDEX IX_vw_SalesSummary ON dbo.vw_SalesSummary(ProductID); -- Setelah ini, hasil agregasi disimpan fisik dan diperbarui otomatis saat OrderDetails berubah

Secara default, view di SQL Server hanyalah query tersimpan yang dijalankan ulang setiap kali dipanggil, sehingga tidak memberi keuntungan performa dibanding menulis query yang sama secara langsung. Indexed view mengubah perilaku ini dengan menyimpan hasil query secara fisik di disk melalui pembuatan unique clustered index pada view tersebut, mirip seperti materialized view pada database lain.

Untuk bisa diberi clustered index, view harus dibuat dengan opsi WITH SCHEMABINDING yang mengunci struktur tabel dasar agar tidak bisa diubah tanpa menghapus dependensi terlebih dahulu, dan query di dalamnya memiliki banyak batasan, misalnya tidak boleh memakai SELECT *, harus memakai COUNT_BIG bukan COUNT, tidak boleh memakai subquery, dan semua kolom yang direferensikan harus menyebutkan nama tabel secara eksplisit.

Keuntungan utama indexed view adalah query yang mengagregasi tabel besar bisa menjadi jauh lebih cepat karena SQL Server cukup membaca hasil yang sudah terangkum, namun konsekuensinya setiap operasi INSERT UPDATE atau DELETE pada tabel dasar akan memicu pembaruan index view secara otomatis, sehingga beban tulis pada tabel sumber akan sedikit meningkat dan harus dipertimbangkan pada sistem dengan volume transaksi tulis yang tinggi.

WITH SCHEMABINDING dan WITH CHECK OPTION pada View

SCHEMABINDING mengunci skema, CHECK OPTION menjaga konsistensi hasil DML

-- WITH SCHEMABINDING: mengunci struktur tabel dasar dari perubahan CREATE VIEW dbo.vw_ActiveCustomers WITH SCHEMABINDING AS SELECT CustomerID, CustomerName, Email FROM dbo.Customers WHERE IsActive = 1; GO -- ALTER TABLE Customers DROP COLUMN Email akan GAGAL selama view ini ada -- WITH CHECK OPTION: mencegah INSERT/UPDATE yang membuat baris hilang dari view CREATE VIEW dbo.vw_HighValueOrders AS SELECT OrderID, CustomerID, TotalAmount FROM dbo.Orders WHERE TotalAmount > 10000000 WITH CHECK OPTION; -- Percobaan berikut akan GAGAL karena hasilnya tidak lagi memenuhi WHERE di atas UPDATE dbo.vw_HighValueOrders SET TotalAmount = 500000 WHERE OrderID = 10; -- Msg 550: baris bertentangan dengan CHECK OPTION dari view

WITH SCHEMABINDING mengikat definisi view secara ketat pada struktur tabel dasarnya, sehingga tabel yang direferensikan tidak dapat diubah strukturnya, misalnya menghapus atau mengganti tipe kolom yang dipakai view, selama view tersebut masih ada. Selain menjadi syarat wajib untuk indexed view, SCHEMABINDING juga berguna sebagai pengaman agar perubahan skema tabel tidak secara tidak sengaja merusak view yang bergantung padanya di aplikasi lain.

WITH CHECK OPTION berfungsi pada view yang bisa menerima operasi DML (updatable view), memastikan bahwa setiap INSERT atau UPDATE yang dilakukan melalui view tersebut menghasilkan baris yang tetap memenuhi kondisi WHERE pada definisi view. Tanpa CHECK OPTION, sangat mungkin terjadi baris yang baru disisipkan atau diubah melalui view langsung menghilang dari hasil SELECT berikutnya pada view yang sama karena tidak lagi memenuhi filter.

Kedua opsi ini menyasar masalah berbeda: SCHEMABINDING melindungi integritas struktural view dari perubahan skema tabel dasar, sedangkan CHECK OPTION melindungi integritas logis data yang dimasukkan melalui view agar tetap konsisten dengan tujuan filter view itu sendiri, dan keduanya sering dipakai bersamaan pada view yang menjadi lapisan akses utama bagi aplikasi eksternal terhadap subset data tertentu. Tanpa CHECK OPTION, developer yang memakai view untuk pembaruan data sering kali tidak menyadari bahwa baris yang baru saja mereka ubah sudah tidak lagi tampak pada hasil SELECT berikutnya.

View dengan UNION ALL sebagai Lapisan Abstraksi Tabel Terpisah

View UNION ALL menyembunyikan pemisahan tabel fisik dari sisi aplikasi

-- Dua tabel transaksi terpisah per tahun, disatukan lewat satu view CREATE VIEW dbo.vw_AllOrders AS SELECT OrderID, CustomerID, OrderDate, TotalAmount, '2025' AS SourceTahun FROM Orders2025 UNION ALL SELECT OrderID, CustomerID, OrderDate, TotalAmount, '2026' AS SourceTahun FROM Orders2026; -- Aplikasi cukup query dbo.vw_AllOrders tanpa tahu data tersebar di dua tabel fisik SELECT CustomerID, SUM(TotalAmount) AS Total FROM dbo.vw_AllOrders WHERE OrderDate >= '2025-06-01' GROUP BY CustomerID;

View yang menggabungkan beberapa tabel melalui UNION ALL berguna sebagai lapisan abstraksi ketika data secara fisik disimpan terpisah, misalnya per tahun atau per cabang, namun aplikasi maupun laporan ingin memperlakukannya sebagai satu sumber data tunggal tanpa perlu tahu detail pemisahan tersebut.

UNION ALL dipilih dibanding UNION karena tidak melakukan pengecekan dan penghapusan baris duplikat, sehingga performanya lebih baik ketika memang tidak ada kemungkinan baris identik muncul di kedua sumber. Pendekatan ini juga memudahkan migrasi data, karena tabel fisik baru bisa ditambahkan ke definisi view kapan pun tanpa mengubah query aplikasi yang sudah ada. Satu konsekuensi yang perlu diperhatikan adalah seluruh kolom pada tiap bagian UNION ALL harus memiliki jumlah dan tipe data yang kompatibel, sehingga penyesuaian tipe sering diperlukan ketika tabel sumber memiliki struktur yang sedikit berbeda.

Kesalahan Umum yang Sering Terjadi

Membuat VIEW Berlapis Terlalu Dalam

VIEW yang memanggil VIEW lain yang memanggil VIEW lain lagi akan membuat query optimizer kesulitan menghasilkan execution plan yang efisien, dan menyulitkan developer melacak dari mana sebenarnya data tertentu berasal.

Mengira VIEW Selalu Mempercepat Query

VIEW biasa (non-indexed) hanya menyimpan definisi query, bukan hasilnya, sehingga query yang berat tetap berat setiap kali VIEW tersebut dipanggil — ia tidak otomatis menjadi cache.

Lupa SCHEMABINDING Membuat Tabel Sumber Tidak Bisa Diubah Sembarangan

VIEW dengan WITH SCHEMABINDING mencegah perubahan struktur tabel sumber (seperti DROP COLUMN) selama VIEW tersebut masih ada, yang bisa membuat developer bingung saat ALTER TABLE tiba-tiba gagal.

Kapan Pendekatan Ini Tidak Cocok Dipakai

VIEW biasa cocok untuk menyederhanakan query kompleks yang sering dipakai ulang dan menyembunyikan detail JOIN dari pengguna akhir, namun tidak memberikan manfaat performa karena query di baliknya tetap dieksekusi penuh setiap saat.

Indexed view memberikan manfaat performa nyata untuk query agregat yang sering diakses dengan data yang jarang berubah, namun menambah overhead saat INSERT/UPDATE/DELETE pada tabel sumber karena indexnya harus ikut diperbarui, sehingga kurang cocok untuk tabel dengan frekuensi tulis yang sangat tinggi.

Ringkasan

VIEW memberikan lapisan abstraksi yang berguna untuk menyederhanakan query kompleks dan menyembunyikan detail implementasi dari pengguna, namun perlu diingat bahwa VIEW biasa tidak menyimpan data secara fisik dan tidak otomatis mempercepat query. Gunakan indexed view hanya ketika benar-benar dibutuhkan performa ekstra pada query agregat yang datanya relatif stabil.

Seri Belajar SQL Server:

← Sebelumnya: Window Function ROW_NUMBER RANK dan PARTITION BY

→ Selanjutnya: Stored Procedure Dasar di SQL Server (segera terbit)