PostgreSQL'de CREATE VIEW bir sorguya ad verir ve o sorguyu tabloymuş gibi kullanmanızı sağlar; veriyi kopyalamaz, view her sorgulandığında arkasındaki SELECT yeniden çalışır. CREATE MATERIALIZED VIEW ise sorgunun sonucunu diskte tablo benzeri bir yapıda saklar; veri ancak REFRESH MATERIALIZED VIEW çalıştırdığınızda tazelenir. Kısacası normal view her zaman günceldir ama her seferinde hesaplanır, materialized view hızlıdır ama son yenilemedeki hâli gösterir.
Bu yazıda iki yapıyı da çalışan örneklerle ele alıyoruz: basit bir view oluşturma, hangi view'lerin otomatik olarak güncellenebildiği, WITH CHECK OPTION ile view dışına satır yazılmasını engelleme, CREATE OR REPLACE VIEW kuralları, bağımlılık hataları, security_barrier ve security_invoker seçenekleri, materialized view yenileme ve REFRESH ... CONCURRENTLY için gereken benzersiz indeks. Tüm çıktılar PostgreSQL 18.1 üzerinde psql ile alınmıştır. Serinin diğer konuları için PostgreSQL öğrenme rehberine bakabilirsiniz.
View nedir, ne işe yarar?
Resmî eğitim bölümü view'i, sık kullandığınız bir sorguya isim vermenin yolu olarak tanıtır: sorguyu her seferinde yazmak yerine view adını bir tablo adı gibi FROM içinde kullanırsınız. Kılavuz bunun ötesinde önemli bir tasarım fikrini de vurgular: tabloların yapısı uygulama büyüdükçe değişebilir, view'ler ise bu ayrıntıları sabit bir arayüzün arkasına saklar. Uygulamanız musteri_ciro adlı bir view okuyorsa, arkadaki tabloları yeniden düzenlediğinizde yalnızca view tanımını güncellemeniz yeter.
View, PostgreSQL kataloglarında bir ilişki (relation) olarak durur; yani tablo, sequence, indeks ve materialized view ile aynı ad alanını paylaşır. Aynı şemada aynı adı taşıyan bir tablo ile bir view birlikte bulunamaz. Şema adı verirseniz (CREATE VIEW rapor.musteri_ciro) view o şemada, vermezseniz search_path içindeki geçerli şemada oluşur. Şema ve arama yolu ayrıntıları veritabanı ve şema oluşturma yazısında anlatılıyor.
Aşağıdaki örnekte müşteri ve sipariş tablolarını birleştirip müşteri başına sipariş sayısı ve toplam tutarı veren bir view tanımlıyoruz. Sorgunun içindeki LEFT JOIN ve GROUP BY ayrıntıları JOIN türleri ve GROUP BY ve aggregate fonksiyonlar yazılarının konusu; burada odak view'in kendisinde.
CREATE TABLE musteri (
id integer PRIMARY KEY,
ad text NOT NULL,
il text NOT NULL,
aktif boolean NOT NULL DEFAULT true
);
CREATE TABLE siparis (
id integer PRIMARY KEY,
musteri_id integer NOT NULL REFERENCES musteri(id),
tarih date NOT NULL,
tutar numeric(10,2) NOT NULL
);
INSERT INTO musteri VALUES
(1, 'Ayşe Yılmaz', 'İzmir', true),
(2, 'Mehmet Kaya', 'Ankara', true),
(3, 'Zeynep Çelik', 'İzmir', false),
(4, 'Can Öztürk', 'Bursa', true);
INSERT INTO siparis VALUES
(1, 1, '2026-10-01', 250.00),
(2, 1, '2026-10-15', 120.50),
(3, 2, '2026-10-03', 990.00),
(4, 4, '2026-10-20', 75.25),
(5, 2, '2026-11-02', 310.00);
CREATE VIEW musteri_ciro AS
SELECT m.id, m.ad, m.il, count(s.id) AS siparis_sayisi,
coalesce(sum(s.tutar), 0) AS toplam
FROM musteri m
LEFT JOIN siparis s ON s.musteri_id = m.id
GROUP BY m.id, m.ad, m.il;
SELECT * FROM musteri_ciro WHERE il = 'İzmir' ORDER BY id; id | ad | il | siparis_sayisi | toplam
----+--------------+-------+----------------+--------
1 | Ayşe Yılmaz | İzmir | 2 | 370.50
3 | Zeynep Çelik | İzmir | 0 | 0
(2 rows)View'i sorgularken eklediğiniz WHERE il = 'İzmir' koşulu, view tanımıyla birleştirilerek tek bir sorgu olarak planlanır. Yani view kendi başına bir ara tablo üretip sonra filtrelenmez; planlayıcı view'in sorgusunu dış sorgunun içine açar. Bu yüzden basit view'ler çoğu durumda doğrudan yazılmış sorguyla aynı planı alır. Planın nasıl okunacağını EXPLAIN ANALYZE yazısında bulabilirsiniz.
CREATE VIEW sözdizimi ve seçenekleri

Kılavuzdaki özet sözdizimi şöyledir; köşeli parantezler isteğe bağlı kısımları gösterir:
CREATE [ OR REPLACE ] [ TEMP | TEMPORARY ] [ RECURSIVE ] VIEW name [ ( column_name [, ...] ) ]
[ WITH ( view_option_name [= view_option_value] [, ... ] ) ]
AS query
[ WITH [ CASCADED | LOCAL ] CHECK OPTION ]- TEMPORARY: view oturum bitince silinir. View'in başvurduğu tablolardan biri geçici tabloysa, siz yazmasanız bile view geçici olarak oluşturulur. Geçici view özel bir şemada yaşadığı için şema adı verilemez.
- RECURSIVE: özyinelemeli view. Kılavuza göre bu, içinde
WITH RECURSIVEbulunan sıradan bir view ile eşdeğerdir ve sütun adı listesi zorunludur. Özyinelemeli sorguların kendisi WITH ve recursive CTE yazısında. - column_name listesi: verilmezse sütun adları sorgudan çıkarılır.
- query: bir
SELECTya daVALUESkomutu olmalıdır. - WITH (...):
check_option,security_barriervesecurity_invokerparametreleri. Hepsi sonradanALTER VIEWile değiştirilebilir.
Sık gözden kaçan bir ayrıntı SELECT * ile ilgilidir. Kılavuzdaki örnek açıkça belirtir: view oluşturulurken * o anda tabloda bulunan sütunlara açılır; tabloya sonradan eklenen sütunlar view'e kendiliğinden girmez. Yeni sütunu görmek istiyorsanız view'i yeniden tanımlamanız gerekir.
Güncellenebilir view: INSERT, UPDATE, DELETE
PostgreSQL basit view'leri otomatik olarak güncellenebilir kabul eder: bu view'lere INSERT, UPDATE, DELETE ve MERGE yazabilirsiniz, sistem komutu alttaki tabloya yönelik eşdeğer komuta çevirir. Bunun için view'in şu koşulların hepsini sağlaması gerekir:
FROMlistesinde tam olarak bir öğe olmalı ve bu öğe bir tablo ya da güncellenebilir başka bir view olmalı.- En üst düzeyde
WITH,DISTINCT,GROUP BY,HAVING,LIMITveyaOFFSETbulunmamalı. - En üst düzeyde
UNION,INTERSECT,EXCEPTgibi küme işlemleri olmamalı. - Seçim listesinde aggregate, window function veya küme döndüren fonksiyon bulunmamalı.
Böyle bir view'de güncellenebilir ve salt okunur sütunlar karışık olabilir. Alttaki tablonun sütununa doğrudan başvuran sütunlar yazılabilir; upper(ad) gibi hesaplanan sütunlara değer atamaya çalışırsanız hata alırsınız. ON CONFLICT UPDATE içeren INSERT komutları da bu view'lerde tam olarak desteklenir.
CREATE VIEW izmir_musterileri AS
SELECT id, ad, il, aktif FROM musteri WHERE il = 'İzmir';
INSERT INTO izmir_musterileri VALUES (5, 'Elif Demir', 'İzmir', true);
UPDATE izmir_musterileri SET aktif = true WHERE id = 3;
INSERT INTO izmir_musterileri VALUES (6, 'Burak Aydın', 'Antalya', true);
SELECT id, ad, il FROM izmir_musterileri ORDER BY id;
SELECT id, ad, il FROM musteri WHERE id = 6; id | ad | il
----+--------------+-------
1 | Ayşe Yılmaz | İzmir
3 | Zeynep Çelik | İzmir
5 | Elif Demir | İzmir
(3 rows)
id | ad | il
----+-------------+---------
6 | Burak Aydın | Antalya
(1 row)Sonuca dikkat edin: Antalya'lı müşteri view üzerinden eklendi ama view'de görünmüyor, çünkü view yalnızca İzmir satırlarını gösteriyor. Kılavuz bu davranışı açıkça anlatır: view'deki WHERE koşulu UPDATE ve DELETE komutlarının hangi satırlara dokunabileceğini sınırlar, ancak INSERT ve UPDATE sonucunda view koşulunu sağlamayan bir satır oluşmasını kendiliğinden engellemez. Bu, özellikle view'i bir yetki sınırı gibi kullanıyorsanız istenmeyen bir durumdur.
WITH CHECK OPTION: LOCAL ve CASCADED

WITH CHECK OPTION eklediğinizde view üzerinden yapılan INSERT, UPDATE ve MERGE komutlarının ürettiği yeni satırlar, view koşulunu sağlıyor mu diye denetlenir. Sağlamayan satır reddedilir. Aynı örneği bu seçenekle yeniden tanımlayalım; ayrıca GROUP BY içeren view'e yazmayı deneyelim:
CREATE OR REPLACE VIEW izmir_musterileri AS
SELECT id, ad, il, aktif FROM musteri WHERE il = 'İzmir'
WITH CHECK OPTION;
INSERT INTO izmir_musterileri VALUES (7, 'Selin Arslan', 'Muğla', true);
UPDATE izmir_musterileri SET il = 'Manisa' WHERE id = 1;
UPDATE musteri_ciro SET toplam = 0 WHERE id = 1;ERROR: new row violates check option for view "izmir_musterileri"
DETAIL: Failing row contains (7, Selin Arslan, Muğla, t).
ERROR: new row violates check option for view "izmir_musterileri"
DETAIL: Failing row contains (1, Ayşe Yılmaz, Manisa, t).
ERROR: cannot update view "musteri_ciro"
DETAIL: Views containing GROUP BY are not automatically updatable.
HINT: To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule.İlk iki komut, Muğla ve Manisa satırları view dışında kalacağı için reddedildi. Üçüncü hata farklı bir kuraldan geliyor: musteri_ciro içinde GROUP BY var, bu yüzden otomatik güncellenebilir değil. PostgreSQL'in ipucu satırı çözümü de söylüyor: böyle karmaşık bir view'e yazmak istiyorsanız bir INSTEAD OF trigger tanımlamalısınız. Kılavuz kural (rule) sistemini de seçenek olarak anar ama trigger'ların anlaşılmasının ve doğru kullanılmasının daha kolay olduğunu belirtir. INSTEAD OF trigger yazımı PostgreSQL trigger oluşturma yazısında anlatılıyor.
View'ler üst üste kurulabildiği için denetimin kapsamı da seçilebilir:
| Seçenek | Ne denetlenir |
|---|---|
| LOCAL | Yalnızca bu view'in kendi koşulu; alttaki view'lerin koşulları, onlar da CHECK OPTION taşımıyorsa denetlenmez |
| CASCADED | Bu view'in ve altındaki tüm view'lerin koşulları |
| Yalnızca WITH CHECK OPTION | CASCADED varsayılır |
CHECK OPTION özyinelemeli view'lerde kullanılamaz ve yalnızca otomatik güncellenebilir, INSTEAD OF trigger'ı ya da INSTEAD kuralı olmayan view'lerde desteklenir. Altta trigger ile güncellenen bir view varsa, üstteki view'in CASCADED denetimi o trigger'lı view'e inmez.
CREATE OR REPLACE VIEW ve bağımlılıklar
CREATE OR REPLACE VIEW var olan bir view'in tanımını yerinde değiştirir. Kuralı katıdır: yeni sorgu eski sorgunun ürettiği sütunları aynı adla, aynı sırayla ve aynı veri tipiyle üretmeli; yalnızca listenin sonuna yeni sütun eklenebilir. Hesaplama yöntemi ise tamamen değişebilir. Değiştirme sırasında yalnızca view'in sorgusu, WITH (...) parametreleri ve CHECK OPTION değişir; sahiplik ve yetkiler korunur. View'i değiştirmek için sahibi (ya da sahip rolün üyesi) olmanız gerekir.
View'ler alttaki tablolara bağımlılık kaydı bırakır. Bu yüzden view'in kullandığı bir sütunun tipini değiştirmek veya view'in dayandığı tabloyu silmek doğrudan mümkün olmaz. Dört durumu art arda deneyelim:
-- 1) Sütun çıkarmaya çalışmak
CREATE OR REPLACE VIEW izmir_musterileri AS
SELECT id, ad, aktif FROM musteri WHERE il = 'İzmir';
-- 2) Sona yeni sütun eklemek
CREATE OR REPLACE VIEW izmir_musterileri AS
SELECT id, ad, il, aktif, upper(ad) AS buyuk_ad FROM musteri WHERE il = 'İzmir'
WITH CHECK OPTION;
-- 3) View'in kullandığı sütunun tipini değiştirmek
ALTER TABLE musteri ALTER COLUMN il TYPE varchar(40);
-- 4) View'in dayandığı tabloyu silmek
DROP TABLE siparis;ERROR: cannot drop columns from view
CREATE VIEW
ERROR: cannot alter type of a column used by a view or rule
DETAIL: rule _RETURN on view musteri_ciro depends on column "il"
ERROR: cannot drop table siparis because other objects depend on it
DETAIL: view musteri_ciro depends on table siparis
HINT: Use DROP ... CASCADE to drop the dependent objects too.Sütun çıkarma reddedildi, sona sütun ekleme kabul edildi. Tip değişikliği ve tablo silme ise view bağımlılığı yüzünden durdu. DROP ... CASCADE önerisini düşünmeden uygulamayın: bu, bağımlı view'leri de siler ve onlara verilmiş yetkiler kaybolur. Güvenli yol genellikle şudur: bir transaction açın, bağımlı view'leri silin, tabloyu değiştirin, view'leri aynı tanım ve yetkilerle yeniden oluşturun, sonra commit edin. Transaction kullanımı BEGIN, COMMIT ve ROLLBACK yazısında, yetkilerin yeniden verilmesi GRANT ve REVOKE yazısında anlatılıyor.
View ve güvenlik: security_barrier, security_invoker
Varsayılan olarak view'in alttaki tablolara erişimi view sahibinin yetkileriyle denetlenir. Bu sayede kullanıcıya tablonun kendisini değil yalnızca view'i açarak belirli sütunları gizleyebilirsiniz. Ancak kılavuzun kurallar ve yetkiler bölümü önemli bir uyarı yapar: sıradan bir view, görünmeyen satırların içeriğini güvenilir biçimde saklayamaz. Kullanıcı, kendi yazdığı ve argümanlarını dışarı sızdıran bir fonksiyonu sorgu koşuluna koyarsa, planlayıcı bu fonksiyonu view'in filtresinden önce çalıştırabilir ve gizli satırlar fonksiyona geçebilir.
security_barrier seçeneği bunu engeller: view'in WHERE koşulları, kullanıcının eklediği koşullardan önce değerlendirilir. Bedeli performanstır; kılavuz bu view'lerin belirgin şekilde yavaş olabileceğini ve bu yüzden seçeneğin varsayılan olarak kapalı olduğunu söyler. Planlayıcı yalnızca LEAKPROOF olarak işaretlenmiş fonksiyon ve operatörleri güvenle öne alabilir. Kılavuz ayrıca bu korumanın sınırlı olduğunu, kullanıcının EXPLAIN veya sorgu sürelerinden dolaylı çıkarım yapabileceğini de not eder.
security_invoker ise yetki denetiminin kime göre yapılacağını değiştirir: true olduğunda alttaki tablolar view sahibinin değil, sorguyu çalıştıran kullanıcının yetkileriyle denetlenir. Alttaki tabloda satır düzeyi güvenlik (RLS) varsa, varsayılanda view sahibinin politikaları uygulanır; security_invoker ile çağıran kullanıcının politikaları uygulanır. Satır güvenliği için Row Level Security yazısına bakın.
CREATE VIEW aktif_musteri WITH (security_barrier) AS
SELECT id, ad, il FROM musteri WHERE aktif;
ALTER VIEW aktif_musteri SET (security_invoker = true);
SELECT relname, reloptions FROM pg_class WHERE relname = 'aktif_musteri';
SELECT pg_get_viewdef('aktif_musteri'::regclass, true); relname | reloptions
---------------+-----------------------------------------------
aktif_musteri | {security_barrier=true,security_invoker=true}
(1 row)
pg_get_viewdef
-----------------
SELECT id, +
ad, +
il +
FROM musteri+
WHERE aktif;
(1 row)pg_get_viewdef fonksiyonu PostgreSQL'in sakladığı view tanımını geri verir; psql içinde \d+ aktif_musteri de aynı tanımı gösterir. Görüldüğü gibi saklanan metin sizin yazdığınız metin değil, ayrıştırılmış sorgunun yeniden üretilmiş hâlidir.
Materialized view: sonucu saklamak
Materialized view da kural sistemini kullanır ama sonucu tablo benzeri bir yapıda kalıcı olarak tutar. Kılavuz onu CREATE TABLE AS ile karşılaştırır: iki fark vardır. Materialized view doğrudan güncellenemez (INSERT veya UPDATE kabul etmez) ve onu oluşturan sorgu saklanır, böylece istediğiniz zaman aynı sorguyla yeniden doldurulabilir. Sorgulandığında veri doğrudan saklanan yapıdan okunur; sorgu yalnızca doldurma sırasında çalışır.
Bu yapı, verinin anlık olarak güncel olması gerekmeyen raporlar için uygundur. Kılavuzdaki örnek, satış temsilcilerinin panosu için günlük satış özetini her gece yenilemektir. Biz de siparişlerden aylık ciro özeti çıkaralım ve yeni bir sipariş ekledikten sonra ne gördüğümüze bakalım:
CREATE MATERIALIZED VIEW aylik_ciro AS
SELECT date_trunc('month', tarih)::date AS ay,
count(*) AS adet, sum(tutar) AS ciro
FROM siparis
GROUP BY 1
WITH DATA;
SELECT * FROM aylik_ciro ORDER BY ay;
INSERT INTO siparis VALUES (6, 3, '2026-11-05', 500.00);
SELECT * FROM aylik_ciro ORDER BY ay; ay | adet | ciro
------------+------+---------
2026-10-01 | 4 | 1435.75
2026-11-01 | 1 | 310.00
(2 rows)
ay | adet | ciro
------------+------+---------
2026-10-01 | 4 | 1435.75
2026-11-01 | 1 | 310.00
(2 rows)Kasım ayına 500 TL'lik sipariş eklenmesine rağmen ikinci sorgu hâlâ bir adet ve 310,00 gösteriyor. Bu bir hata değil, materialized view'in tanımı budur: içerik ancak yenilendiğinde değişir. Normal bir view aynı anda yeni siparişi hemen gösterirdi.
CREATE MATERIALIZED VIEW komutunda WITH NO DATA derseniz yapı boş ve taranamaz (unscannable) olarak oluşur; ilk REFRESH yapılana kadar sorgulanamaz. Sorgu, güvenlik açısından kısıtlı bir işlem olarak çalışır ve çalışırken search_path geçici olarak pg_catalog, pg_temp yapılır. Bu yüzden sorgudaki tablo ve fonksiyon adlarını şema adıyla yazmak sürprizleri önler. Geçici materialized view desteklenmez.
REFRESH MATERIALIZED VIEW ve CONCURRENTLY
REFRESH MATERIALIZED VIEW içeriği tamamen değiştirir: eski veri atılır, saklanan sorgu yeniden çalışır. Komutu çalıştırmak için materialized view üzerinde MAINTAIN yetkisi gerekir. Düz REFRESH çalışırken diğer oturumların okumalarını engelleyebilir. CONCURRENTLY seçeneği okumaları kilitlemeden yeniler, ancak bir ön koşulu vardır: materialized view üzerinde yalnızca sütun adlarından oluşan, WHERE içermeyen ve tüm satırları kapsayan en az bir UNIQUE indeks bulunmalıdır.
REFRESH MATERIALIZED VIEW CONCURRENTLY aylik_ciro;
CREATE UNIQUE INDEX aylik_ciro_ay ON aylik_ciro (ay);
REFRESH MATERIALIZED VIEW CONCURRENTLY aylik_ciro;
SELECT * FROM aylik_ciro ORDER BY ay;ERROR: cannot refresh materialized view "public.aylik_ciro" concurrently
HINT: Create a unique index with no WHERE clause on one or more columns of the materialized view.
CREATE INDEX
REFRESH MATERIALIZED VIEW
ay | adet | ciro
------------+------+---------
2026-10-01 | 4 | 1435.75
2026-11-01 | 2 | 810.00
(2 rows)İlk deneme benzersiz indeks olmadığı için reddedildi; indeks eklendikten sonra yenileme başarılı oldu ve Kasım satırı iki siparişi, 810,00 tutarı gösterdi. Kılavuz iki yöntemi şöyle karşılaştırır: çok satırı etkileyen yenilemelerde düz REFRESH daha az kaynak kullanır ve daha çabuk biter; az satır değiştiğinde CONCURRENTLY daha hızlı olabilir. Hangisi seçilirse seçilsin, aynı materialized view üzerinde aynı anda yalnızca bir REFRESH çalışabilir.
PostgreSQL 18 sürüm notlarına göre artık B-tree dışındaki benzersiz indeksler de, indeks türü eşitliği desteklediği sürece, materialized view'lerde kullanılabiliyor. Aynı sürümle COPY TO doldurulmuş materialized view satırlarını doğrudan kopyalayabiliyor. Tüm yenilikler için PostgreSQL 18 yenilikleri yazısına bakın.
WITH NO DATA ile yenileme, yapıyı boşaltıp taranamaz duruma getirir ve kullandığı depolama alanını serbest bırakır. Bu durumda CONCURRENTLY kullanılamaz, çünkü eşzamanlı yenileme yalnızca doldurulmuş bir materialized view üzerinde çalışır:
REFRESH MATERIALIZED VIEW aylik_ciro WITH NO DATA;
SELECT * FROM aylik_ciro;
REFRESH MATERIALIZED VIEW aylik_ciro;
SELECT relname, relkind, relispopulated FROM pg_class
WHERE relname IN ('musteri_ciro', 'aylik_ciro', 'siparis') ORDER BY relname;REFRESH MATERIALIZED VIEW
ERROR: materialized view "aylik_ciro" has not been populated
HINT: Use the REFRESH MATERIALIZED VIEW command.
REFRESH MATERIALIZED VIEW
relname | relkind | relispopulated
--------------+---------+----------------
aylik_ciro | m | t
musteri_ciro | v | t
siparis | r | t
(3 rows)pg_class kataloğundaki relkind sütunu nesnenin türünü gösterir: v view, m materialized view, r sıradan tablo. relispopulated ise materialized view'in sorgulanabilir olup olmadığını söyler. Ayrıca kılavuz, tanımda ORDER BY olsa bile REFRESH sonrasında satır sırasının korunmasının garanti edilmediğini belirtir; sıralama gerekiyorsa okurken ORDER BY yazın.
View mı, materialized view mı, tablo mu?

| Özellik | View | Materialized view | CREATE TABLE AS |
|---|---|---|---|
| Veriyi saklar mı | Hayır, her sorguda hesaplanır | Evet | Evet |
| Güncellik | Her zaman güncel | Son REFRESH anı | Oluşturma anı |
| Sorgu saklanır mı | Evet | Evet, REFRESH için | Hayır |
| Doğrudan INSERT/UPDATE | Basit view'lerde evet | Hayır | Evet |
| İndeks eklenebilir mi | Hayır (alttaki tabloya eklenir) | Evet | Evet |
| Geçici sürüm | TEMP VIEW var | Yok | TEMP TABLE var |
Kural olarak: sorgu hızlıysa ve verinin her an güncel olması gerekiyorsa normal view; sorgu pahalı ve gecikmeli veri kabul edilebiliyorsa materialized view; veriyi bağımsız olarak değiştirmek istiyorsanız gerçek bir tablo kullanın. Genel performans ayarları için PostgreSQL performans optimizasyonu yazısına bakabilirsiniz.
Sık yapılan hatalar
- View'in veriyi sakladığını sanmak: normal view her seferinde sorguyu çalıştırır. Yavaş bir sorguyu view içine almak onu hızlandırmaz.
- Materialized view'in kendiliğinden güncellendiğini sanmak: yukarıdaki örnekte görüldüğü gibi yeni satırlar
REFRESHyapılana kadar görünmez. - CONCURRENTLY için indeksi unutmak:
WHEREiçermeyen, ifade içermeyen birUNIQUEindeks şarttır. - CHECK OPTION kullanmadan view'i yetki sınırı yapmak: güncellenebilir view üzerinden view dışına satır eklenebilir.
- SELECT * ile yeni sütun beklemek: view oluşturulduğu anki sütun listesini tutar.
- CREATE OR REPLACE ile sütun çıkarmak veya sırasını değiştirmek: yalnızca sona ekleme yapılabilir; aksi hâlde view'i silip yeniden oluşturmanız gerekir.
- DROP ... CASCADE'i hemen uygulamak: bağımlı view'ler ve yetkileri de silinir; önce neyin bağımlı olduğunu hata mesajındaki DETAIL satırından okuyun.
Sık Sorulan Sorular
View performansı artırır mı?
Normal view tek başına artırmaz; yalnızca sorguyu paketler. Planlayıcı basit view'leri dış sorguyla birleştirdiği için genellikle yavaşlatmaz da. Pahalı bir hesaplamayı tekrar tekrar yapmamak istiyorsanız materialized view kullanmalısınız.
Materialized view otomatik yenilenebilir mi?
CREATE MATERIALIZED VIEW sözdiziminde kendiliğinden yenileme için bir seçenek bulunmaz. Kılavuzun önerdiği yöntem, yenilemeyi zamanlanmış bir işle, örneğin her gece REFRESH MATERIALIZED VIEW çalıştırarak yapmaktır.
View üzerinden UPSERT yapabilir miyim?
Evet. Kılavuza göre otomatik güncellenebilir view'lerde INSERT ... ON CONFLICT UPDATE tam olarak desteklenir. Sözdizimi için UPSERT ve MERGE yazısına bakın.
View'in tanımını nasıl görürüm?
psql'de \d+ view_adi yazabilir veya pg_get_viewdef('view_adi'::regclass, true) fonksiyonunu çağırabilirsiniz. psql komutları psql komutları yazısında.
Geçici bir view oluşturabilir miyim?
Evet, CREATE TEMP VIEW oturum sonunda silinen bir view oluşturur. Geçici materialized view ise desteklenmez; CREATE MATERIALIZED VIEW sayfası bunu açıkça belirtir.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: PostgreSQL öğrenme rehberi · Trigger oluşturma · Row Level Security · İndeks türleri · CREATE FUNCTION · PostgreSQL performans optimizasyonu