Merhaba Arkadaşlar,

Bu yazımda sizlere Partition yapıda olmayan bir tabloyu  DBMS_REDEFINITION paketini kullanarak Online olarak Partitionlı yapıya dönüştürmeyi anlatacağım. Bu yazımı okumadan önce Partitioning ile ilgili genel kavramları anlatan şu yazımı okumanızı tavsiye ederim.

oracle partition

Kurumların Çalışan production sistemlerinde kritik bir çalışma yapılırken kesinti ( downtime ) almamak yada minimum kesinti almak çok önemlidir. Bu kritik durumlara karşı Oracle kesinti süresini minimize etmeye yada yok etmeye çalışan teknolojiler sunmaktadır. İşte bunlardan biriside Oracle 9i ile Oracle dünyasına tanıtılan DBMS_REDEFINITION paketidir. Bu paket ile Tablolar üzerinde kesinti almadan ( Online bir şekilde ) eskiden kesinti alarak yaptığımız bir çok operasyonu bu paketi kullanarak Online olarak yapabiliyoruz. Kesinti almadan bu paketi kullanarak Tablolar üzerinde yaptığımız operasyonlardan bazıları aşağıdaki gibidir.

  • Partition Yapıda olmayan bir Tabloyu Partitionlı yapıya dönüştürme
  • Index i olmayan bir Tabloyu (Heap Table) İndexli yapıya dönüştürme
  • Tabloya Kolon ekleme,Çıkarma ve Kolon ismini değiştirme
  • Tablonun Storage ( Depolama ) parametrelerini değiştirme
  • Bir tabloyu Reorganize etme

Production sistemlerde büyük tablolar için çok sıklıkla kullanılan yukardaki işlemleri Online olarak yapma çok önemli ve hayatidir. Bu yüzden yukardaki işlemleri yaparken DBMS_REDEFINITION paketinin bizlere sunduğu güzelliklerden mutlaka faydalanın derim.

Peki DBMS_REDEFINITION ile  Online Table Partitioning yaparken Oracle arka planda ne yapıyor ? DBMS_REDEFINITION paketi ile Table Partitioning olayını aşağıdaki resim özetlemektedir.

redefinition

Peki Oracle bu Paketi kullanarak Redefinition Partitioning işlemini arka plandaki nasıl yapıyor ? İlgili işlemin çalışma adımları aşağıdaki gibidir.

  1. Oracle ilgili ana tabloyu Materalized View e dönüştürüp ana tablonun datalarını bu view e aktarır.
  2. Aynı anda Ana tabloda Materalized view log u oluşturup tabloya online gelen transactionları buraya yönlendirir.
  3. Ana Tablo üzerindeki Tüm değişiklikler gerçekleştirildikten sonra bu değişiklikler Ara tablo dediğimiz interim table a aktarılır. Bu tablo partitionlı yapıda olduğu için ilgili veriler tabloya insert edilirken her satır uygun olduğu partition a gider.
  4. Son olarak Data dictionary de Ana tablo ( Fatura ) ile Ara tablonun ( Fatura_old )isimleri birbirleriyle değiştirilir. Böylece Ana tablo ilk durumda oluşturulan partitionlı yapıdaki tabloya dönüşmüş olur.

Şimdi Partitionlı yapıda olmayan bir tabloyu bu yöntemi kullanarak Partitionlı yapıya dönüştürmeyi önceki yazıda örnek verdiğim Belediyenin Fatura tablosu üzerinden örnekle ilgili kodları vererek anlatacağım. Örnek Fatura tablosunun scripti ve bazı dataları aşağıdaki gibidir.

SQL> CREATE TABLE MSDEVECI.FATURA
 (
 MUSTERI_ID NUMBER PRIMARY KEY,
 ADI VARCHAR2(50 BYTE),
 BORC NUMBER,
 FATURA_TARIHI DATE
 )

SQL> select * from msdeveci.fatura;

data

Öncellikle veritabanı üzerinden fatura tablosunun partitionlı yapıda olup olmadığını aşağıdaki gibi sorguluyorum. Sorguyu çalıştırdığım zaman boş cevap geliyor. Yani tablo partitionlı yapıda değildir.

select * from dba_tab_partitions where table_name='FATURA';

Redefinition ile Table partitioning örneğini yapmaya başlamadan önce Orjinal Tabloyla (Fatura adlı tablo) aynı kolon yapısına sahip ve partition lı yapıda ara ( interim table ) bir tablo ( Fatura_old adında ) oluşturmamız gerekiyor. ( Son adımda bu ara tablo isim değiştirerek Ana tablonun yerini alacak. )  Yukarda belirttiğim interim table dediğimiz Range Partitionyapısına uygun ara tabloyu fatura_old adıyla oluşturuyoruz. Fatura_old tablosunun scripti aşağıdaki gibidir.

CREATE TABLE MSDEVECI.FATURA_OLD
 (
 MUSTERI_ID NUMBER PRIMARY KEY,
 ADI VARCHAR2(50 BYTE),
 BORC NUMBER,
 FATURA_TARIHI DATE
 )
 PARTITION BY RANGE(FATURA_TARIHI)(
 PARTITION Fatura201301 VALUES LESS THAN(TO_DATE('01/01/2013','DD/MM/YYYY')),
 PARTITION Fatura201302 VALUES LESS THAN(TO_DATE('01/02/2013','DD/MM/YYYY')),
 PARTITION Fatura201303 VALUES LESS THAN(TO_DATE('01/03/2013','DD/MM/YYYY')),
 PARTITION Fatura201304 VALUES LESS THAN(TO_DATE('01/04/2013','DD/MM/YYYY')),
 PARTITION Fatura201305 VALUES LESS THAN(TO_DATE('01/05/2013','DD/MM/YYYY')),
 PARTITION Fatura201306 VALUES LESS THAN(TO_DATE('01/06/2013','DD/MM/YYYY')),
 PARTITION Fatura201307 VALUES LESS THAN(TO_DATE('01/07/2013','DD/MM/YYYY')));

Yukardaki scripti çalıştırıp fatura_old adlı interim table ı oluşturdum. Redefinition işlemine başlamadan önce  Ana tablomuzun ve ara tablomuzun bu işlem için uygun olup olmadığını DBMS_REDEFINITION paketinin CAN_REDEF_TABLE procedure unu çalıştırarak kontrol ediyoruz.

— Primary key li olan tablonun kontrolü için aşağıdaki script çalıştırılır. Benim tablomda primary key olduğu için aşağıdaki scripti çalıştırdım.

SQL> EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE('MSDEVECI', 'fatura',1);

— Primary key yoksa ROWNUM ile kontrol etmek için aşağıdaki script çalıştırılır.

SQL> EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE('MSDEVECI', 'fatura',2);

Yukardaki scriptlerden uygun olanı çalıştırıp tablonun redefinition işlemi için uygun olduğunu teyit ettikten sonra Redefinition işlemine başlayabiliriz. Aşağıdaki scriptde 1.kısımda Redefinition işlemini DBMS_REDEFINITION paketinin START_REDEF_TABLE procedure unu Primary key üzerinden çalıştırdığımızda tablonun datalarını taşırız.

2. kısımda tabloya ait Indexler,Triggerler, Constraintler, Grant leride DBMS_REDEFINITION  paketinin COPY_TABLE_DEPENDENTS procedure uyle taşınan script bulunmaktadır. Burada script çalıştırıldığında önce ilk kısım taşınır ve Tablonun dataları taşınır daha sonra 2.kısım çalışır ve tablonun geriye kalan yukardaki gereksinimleri taşınır.

DECLARE
 redefinition_errors PLS_INTEGER := 0;
 BEGIN
-- 1.Kısım

DBMS_REDEFINITION.START_REDEF_TABLE (
 uname => 'MSDEVECI'
 ,orig_table => 'fatura'
 ,int_table => 'fatura_old'
 ,col_mapping => NULL
 ,options_flag => DBMS_REDEFINITION.CONS_USE_PK
 );

-- 2.kısım

DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS (
 uname => 'MSDEVECI'
 ,orig_table => 'fatura'
 ,int_table => 'fatura_old'
 ,copy_indexes => 0
 ,copy_triggers => TRUE
 ,copy_constraints => TRUE
 ,copy_privileges => TRUE
 ,ignore_errors => TRUE
 ,num_errors => redefinition_errors
 ,copy_statistics => FALSE
 ,copy_mvlog => FALSE);
IF (redefinition_errors > 0) THEN
 DBMS_OUTPUT.PUT_LINE('>>> AUDIT_COUNTER_RD to AUDIT_COUNTER failed: ' || TO_CHAR(redefinition_errors));
 END IF;
END;
 /

Yukardaki scripti çalıştırdıktan sonra Redefinition işlemini bitirmek için DBMS_REDEFINITION paketinin  FINISH_REDEF_TABLE procedure u nu aşağıdaki gibi çalıştırıyoruz.

begin
DBMS_REDEFINITION.FINISH_REDEF_TABLE (
 uname => 'MSDEVECI'
 ,orig_table => 'fatura'
 ,int_table => 'fatura_old'
 );
 END;

Yukardaki scripti çalıştırdıktan sonra Redefinition işlemini bitiriyoruz. FINISH_REDEF_TABLE procedure u ile  Data dictionary de Ana tablo ( Fatura ) ile interim table ın ( Fatura_old )isimlerini değiştirilir. Böylece Ana tablo ilk durumda oluşturulan partitionlı yapıdaki tabloya dönüşmüş olur.

Çok büyük tabloların taşınması sırasında FINISH_REDEF_TABLE  procedure unun çok çok uzun sürmemesi için Redefinition işlemini başlattığımız script tamamlandıktan sonra finish procedure unu çalıştırmadan önce DBMS_REDEFINITION paketinin SYNC_INTERIM_TABLE procedure unu çalıştırarak ara tablo dediğimiz fatura_old tablosuyla fatura tablosu arasında ki son senkronizasyon da gerçekleştirilir. Bu procedure u çalıştırıp tamamladıktan FINISH_REDEF_TABLE  procedure u daha kısa sürede tamamlanır. SYNC_INTERIM_TABLE procedure unun ilgili scripti aşağıdaki gibidir.

BEGIN
 DBMS_REDEFINITION.SYNC_INTERIM_TABLE('MSDEVECI', 'fatura', 'fatura_old');
 END;
 /

Ben genelde Redefinition ile partitioning yapılırken eğer tablom çok büyükse aşağıdaki sırada procedure lerimi çalıştırıyorum.

CAN_REDEF_TABLE —> START_REDEF_TABLE ->> COPY_TABLE_DEPENDENTS  ——>                                                  —–>  SYNC_INTERIM_TABLE —> FINISH_REDEF_TABLE

FINISH_REDEF_TABLE  procedure unu çalıştırdıktan sonra fatura tablom partitionlı hale gelmiş oldu. Bunun ispatı yukarda da verdiğim scripti tekrar çalıştırdığımda sonucu aşağıdaki gibi oluyor. Buradan da görüldüğü gibi fatura tablom partitionla yapıya dönüşmüş oldu.

select * from dba_tab_partitions where table_name='FATURA';

Data2

İlk yazımda bahsettiğim gibi mayıs ayına ait herhangi bir müşteriye ait veriyi sorguladığımızda Oracle tüm verileri değil sadece mayıs ayına ait partitiondan sorgular. Partitiona göre veri sorgulama aşağıdaki gibi yapılır.

 select * from fatura partition(Fatura201306) where musteri_id=57052;

data3

Yukardaki sorgunun execution planını çalıştırdığımızda ilgili veriye aşağıdaki gibi partitiondan eriştiğini görebiliyoruz.

data1

Böylece bu yazımın daha sonuna gelmiş bulunmaktayım bir sonraki yazıda görüşmek dileğiyle Esen kalın..

Reklamlar

Bir Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Google+ fotoğrafı

Google+ hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Connecting to %s