Oracle DML Error Logging

Herkese Selam,
Bu yazıda sizlere ekstra bir geliştirme yapmadan gerçeklediğimiz DML operasyonlarında hata alan kayıtları loglamayı göstereceğim. Umarım farkındalık anlamında faydalı bir yazı olur.

Özellikle bulk data ile insert/update/delete işlemleri yaparken bir kayıtta yaşanacak bir problemden dolayı belkide saatler süren bir işlemi başarılı bir şekilde sonlandıramıyoruz. Buda oldukça fazla süre kaybetmemize sebebiyet vermekte. Oracle 10g R2 ile hayatımıza giren DBMS_ERRORLOG paketi sayesinde DML işlemleri sırasında hataya sebebiyet veren kaydı belirlediğimiz bir tabloya loglayıp yola devam edebilmekteyiz. Peki biz bu paketin yaptığı işi manuel yapamazmıyız? Cevap: Evet. Ancak harcadığımız efor çok daha fazla olacak ve uygulama performansını düşüreceğiz (Ekstra fazlaca kod ve obje).

Şimdi bir örnek üzerinden gidelim ve sistemin nasıl işlediğini görelim;
İlk etapta içinde 1001 kayıt olan bir tablo yaratıyorum.

CREATE TABLE hr.source
AS
       SELECT LEVEL ID,
              'data' || MOD (LEVEL, 1001) DESCRIPTION,
              DECODE (MOD (LEVEL, 1001), 1, NULL, 'excol') EXCOL
         FROM DUAL
   CONNECT BY LEVEL <= 1001;

Tablomu doldururken DESCRIPTION kolonununda sonucu 8 karakter olan 1 data oluşmasını sağladım.
EXCOL kolonunda ise sonucu NULL olan tek kayıt oluşmasını sağladım. Oluşan 999 kayıdı benim için sorunsuz bir data olarak içeri almayı planlıyorum. Şimdi bu 2 datanın giremeyeceği bir metadataya sahip örnek bir tablo yaratıyorum. Bu tablo benim için hr.source tablosundan datayı alıp yazacağım hedef tablo gibi düşünebiliriz. Tıpkı ETL processinin ilk adımı olan Extraction adımı gibi.

CREATE TABLE hr.target
(
   nid            NUMBER,
   ndescription   VARCHAR2 (7),
   EXCOL          VARCHAR2 (8),
   CONSTRAINT ck_excol CHECK (nvl(LENGTH (excol),0) = 5)
);

Datayı yazacağımız hedef tabloyu oluşturdum. ndescription alanını hr.source.description alanından besleyeceğim. Burada tek bir kaydın 8 karakter olduğunu biliyorum o yüzden bu kolonu max:7 karakter alabilecek şekilde yarattım. EXCOL kolonunuda hr.source.excol kolonundan besleyeceğim bu kolonada source tablosundan içeriği null olan tek kayıt oluşmasını sağlamıştım bu kayıdın tabloya girememesi içinde bir check constraint tanımladım.

İkinci adım olarak target tablomuza giremeyecek hatalı kayıtları yazacağımız ERRORLOG tablosunu oluşturmaya geldi. Bu tabloyu DBMS_ERRLOG paketini kullanarak oluşturuyoruz.

EXEC DBMS_ERRLOG.CREATE_ERROR_LOG (-
   dml_table_name           =>  'TARGET', -
   err_log_table_name       =>  'ERR_TARGET_DQ', -
   err_log_table_owner      =>  'HR', -
   err_log_table_space      =>   NULL, -
   skip_unsupported         =>   FALSE);

Evet errorlog tablomuzu oluşturduk ancak ilerlemeye başlamadan önce DBMS_ERRLOG.CREATE_ERROR_LOG paketinin aldığı parametreleri inceleyelim.

dml_table_name             :  Hangi tablomuzda aldığımız DML hatalarını loglayacağız.
err_log_table_name     :  Hatalı kayıtlar hangi tabloya loglanacak.
err_log_table_owner    :  Oluşturulacak log tablosu hangi user altında oluşturulacak. (Default olarak kodun çalıştırıldığı user altında yaratılıyor)
err_log_table_space      : Yaratılacak tablonun hangi tablespace altında yaratılacağını söyleyebiliriz. (Default olarak kodun çalıştırıldığı user altında yaratılıyor)
skip_unsupported         :  Bu alt yapıda bazı veri tipleri desteklenmemekte. LOB ve Long gibi alanlar. Eğer bu parametre TRUE yapılırsa dml_table ‘ımız içerisinde desteklenmeyen bir veritipine sahip bir alan var ise prosedürün çalışması sonlanmaz ancak bu alanlar ignore edilir. FALSE olarak setlenir ise desteklenmeyen bir veritipi var ise dml_table da. Prosedür çalıştırıldığında hata alarak sonlanır. (Default olarak False)

Bir önceki adımda ERRORLOG tablomuzu oluşturmuştuk şimdi bu tablonun nasıl oluştuğuna bakalım.

descerrtable

 

Birde Orjinal Target tablomuzu görelim.

target

 

 

Evet 2 tabloyu incelediğimizde dikkat etmemiz gereken en büyük fark kolonlarımızın hepsinin VARCHAR2(4000) şeklinde yaratıldığı. Böylelikle ana tablomuda hataya sebebiyet veren tüm kayıtları bu tabloya yazabilir duruma geldik.

Şimdi test case’imiz run edip sonucu inceleyelim.

 

INSERT INTO hr.target (NID, NDESCRIPTION, EXCOL)
   SELECT ID, DESCRIPTION, EXCOL FROM hr.source
        LOG ERRORS INTO ERR_TARGET_DQ REJECT LIMIT UNLIMITED;

Insert operasyonumuz başarılı bir şekilde bitti. Şimdi log tablomuza bakalım neler olmuş.

SELECT * FROM ERR_TARGET_DQ;

result

Evet görüldüğü üzere TARGET tablomuza giremeyen 2 kayıt neden giremediği ile ilgili ayrıntılı bilgi ile LOG tablomuza girmiş oldu. Şimdi hem log hemde target tablomuza count atalım.

SELECT COUNT(*) FROM HR.TARGET;   -- 999
SELECT COUNT(*) FROM HR.ERR_TARGET_DQ; -- 2

Evet 2 tablomuzda da beklediğimiz gibi toplam SOURCE tablomuzdaki 1001 kaydın 999’u TARGET’da kalan 2 tanesi log tablomuza düşmüş durumda. Şimdi transaction ı ROLLBACK edip yeniden count atalım.

ROLLBACK;
SELECT COUNT(*) FROM HR.TARGET;        -- 0
SELECT COUNT(*) FROM HR.ERR_TARGET_DQ; -- 2

Evet görüldüğü üzere TARGET tablomuzdaki tüm kayıtlar rollback edilirken LOG tablomuzdaki kayıtlar ROLLBACK edilmedi. Bunun nedeni bu log mekanizmasının AUTONOMOUS TRANSACTION mantığı ile çalışmasıyla ilintili. Yani log mekanizması yaptığımız commit veya rollback’den etkilenmiyor. Kendisi otonom olarak çalışıyor.

Bu alt yapı Oracle’da uzun süreden beri var olmasına karşın çok sık kullanılmadığını düşünüyorum ancak özellikle küçük veya orta ölçekli DWH sistemlerinde Extraction fazını implemente ederken fonksyonel bir recycle mekanizması kurmak için oldukça ideal ve kullanışlı olacağını düşünüyorum.

KAYNAKLAR:
https://docs.oracle.com/html/B14258_02/d_errlog.htm

http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_errlog.htm#CEGBBABI

Advertisements

About ... from Emrah METE

Bilgisayar Mühendisi
This entry was posted in Oracle, Root, Uncategorized and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s