Monday, June 8, 2009

MATERIALIZE VIEW

Uygulamanın performansını arttırmak için çok güzel bir çözüm yöntemidir.

Uzak DB’deki verileri kendi DB’nizde toplayabilir ve onlar üzerinde uzakta çalışıyormuş gibi işlemler yapabilirsiniz.

Çok büyük tablolara aynı işlem yada işlem tipleri için sürekli erişmekten ise işinize yarayacak biçimleri ile performans artışı sağlayabilirsiniz. Birden fazla tablo üzerinde sürekli yaptığınız join işlemini belirli zaman aralıklarında yaparak performan ve zaman kazancı sağlayabilirsiniz. Bunun dezavantajı güncel veriler üzerinde işlem yapamamış olmanızdır. Verinizin güncelliği MATERIALIZE VIEW nin tekrar yüklenme zamanı olacaktır.

MATERIALIZE VIEW lerin normal View’lerden en büyük farkı tablo gibi diskinizde fiziksel bir yer kaplamasıdır. Normal View’ler ile işlem yaparken kaynak tablalara erişirsinizi. Ama MATERIALIZE VIEW lerde ise durum farklıdır. MATERIALIZE VIEW yüklenirken kaynak tablolara erişim yapılır ve tekrar yüklenene kadar yüklenmiş veriler üzerinde işlem yapılır.

Bu durumda aklınıza söyle bir soru gelebilir. MATERIALIZE VIEW oluşturacağıma tablo oluştururum diyebilirsiniz ama…

Tablo oluştururken kaynak tabloları kullanacaksınız. Ama bir süre sonra sizin oluşturduğunuz tablo ile kaynak tablonun bütünlüğü bozulacak. Bu durumda tabloya tekrardan insert işlemi yapmanız gerekecektir.

Materialized view, normal viewlerden farklı olarak tablolar gibi diskte yer kaplar. Refresh grubuna göre belirli aralıklarla viewi oluşturan sorgu çalıştırılıp, dönen kayıtlar veritabanında tutulur. İçeriği sorguya göre güncellenen bir tablo gibi düşünebilirsiniz.

MATERIALIZE VIEW ile bu yükleme işi için belirli zaman aralıkları belirleyebilirsiniz. Veri Ambarlarında bu işlemin karşılığı olarak ETL süreci örnek verilebilinir. ETL süreci ile Kaynak tablolardan Hedef tablolarınıza scheduler edilmiş Paketler ile yükleme yapılır.

Salt okunur (read only) bir MATERIALIZE VIEW veri değişikliklerini kaynak tabloya aktarmaz ama siz eğer güncellenebilir (update) MATERIALIZE VIEW oluşturursanız bu değişiklikler kaynak tabloya aktarılacaktır. (tavsiye etmem kontrolu zor olabilir. İstenmeyen sonuçlar doğurur. Git tabloyu kendin update et.)

Kaynak tablolarda İndex kullanmak mantıklı bir yaklaşımdır. Çünkü sürekli olarak bu tablolardan belli koşullarda veri çekeceğiz veri çekme işleminin hızlı olması için bu gereklidir. Ama bu tabloların Index kullanmaya elverişli olması gerekir. Index kullanmanın yanında tablo istatistiklerini almanın da faydasını göreceksiniz.


Complex Materialized Views

Complex MV ler fast refresh'i desteklemez.

complex MV derken bir bakıma Join işlemini kastediyoruz yada belirli bir kısıtlamaların olmasını. Bu kısıtlamaların bazılarına şu örneleri verebiliriz. DISTINCT, UNIQUE, INTERSECT, MINUS, UNION ALL, CONNECT BY, aggregate fonksiyonları(sum ,avg, vb..).

Complex Materialized View işleminde join işlemi MV refresh edilirken yapılır.



Yukarıdaki örnekte anlatmak istediği söyle birşey. Complex Materialized View lerde join işlemi MV olşturuken yapılır ise fast refresh (sadece yapılan değişikleri aktarma) mümkün olmayacaktır. Bütün tablo'nun alınması gerekecektir. Bu durumda complete refreshes(komple doldurma) işleminin yapılması gerekecektir.

Veritabanızda MV oluşturak iseniz ve MV nin source tabloları cok büyük olduğu için complete refresh sizin için perfrmans sorununa sebeb oluyor ise fast refresh yapısını kullanmak isteyeceksiniz. Fakat complex view kullanıyorum bu işi nasıl aşacağım olayına gelince ise Simple Materialized Views with a Joined View sizi kurtaracaktır. View'ler üzerinde join işlemi yaparak sorunu halletmiş olabiliriz.

Birbirine bağlı Materialize View oluşturulması (Nested Materialized View).

Bence aslında MV ye bir nebze tablo diyebiliriz. (Ama biz yl söylemeyelim.) elimizde bir MV var v yeni bir tane daha oluşturmak istiyoruz. Yenisini oluştururken önceki MV yi kulanabiliriz. tablo yaratırken nasıl bir başka tabloyu referans alabiliyor isek burada da aynı işlemi yapabiliriz.

Oracle dökümanından aldığım ufak bir örnek ile acıklama yapalım.


CREATE MATERIALIZED VIEW LOG ON sales WITH ROWID;
CREATE MATERIALIZED VIEW LOG ON customers WITH ROWID;
CREATE MATERIALIZED VIEW LOG ON times WITH ROWID;

-- tablolardaki değişikleri yakalamak için view log oluşturuyoruz.

CREATE MATERIALIZED VIEW referans_alinacak_MV
REFRESH FAST ON COMMIT AS --sadece değişikleri yükle drop create mantığı ile çalışma
SELECT c.cust_id, c.cust_last_name, s.amount_sold, t.time_id,
t.day_number_in_week, s.ROWID srid, t.ROWID trid, c.ROWID crid
FROM sales s, customers c, times t --kaynak tablolarımız bunlar.
WHERE s.time_id = t.time_id AND s.cust_id = c.cust_id;


--şimdi bu MV yi kullanarak yeni bir MV oluşturalım.

--referans olacak olan MV için log oluşturmak gerekiyor. Boylece değişikler takip edilmiş olacak.
--Log mekanizması oluşturulmak zorundadır.a
CREATE MATERIALIZED VIEW LOG ON join_sales_cust_time
WITH ROWID (cust_last_name, day_number_in_week, amount_sold)
INCLUDING NEW VALUES;

CREATE MATERIALIZED VIEW yeni_olusturdugum_MV
REFRESH FAST ON COMMIT AS
SELECT COUNT(*) cnt_all, SUM(amount_sold) sum_sales, COUNT(amount_sold)
cnt_sales, cust_last_name, day_number_in_week
FROM referans_alinacak_MV --kaynak tablolar yerine MV kullanılıyor.
GROUP BY cust_last_name, day_number_in_week;

Nested bağlı bir view oluşturulduğunda bunun fast refreshed olmasını bekleyemeyiz.

1 comment:

hellespontos said...

bro!... güzel bir anlatım olmuş...
query_rewrite_enabled true yapılırsa sql sorgusu çalıştırıldığında ana tablo yerine mv yönlecektir. 9i den sonra 10 g ile birlikte default true olarak gelmektedir. güncel veriler ile çekilmek isteniyorsa false edilmesi gerekmektedir. eğer mv den veri çekilmek isteniyorsa sorgu mv i işaret edecek şekilde yazılmalıdır.

Ferhan Tekin