Hurriyet

12 Aralık 2013 Perşembe

Oracle Veritabanı: Fazladan Kullanılan Yerin Geri Kazanılması - Reclaiming Wasted Space

Fazladan kullanılmış olarak belirlenen yerler zaman içinde çok fazla update, delete, insert ifadeleriyle birlikte oluşan boş bloklardır. Bu bloklar tekrar yerleştirilirse daha önceden boş olarak gözükmeyen yerler veritabanı tarafından görülmeye başlanacaktır. Bu boşluklar fragmante edilmiş boş alanlar olarak tanımlanmaktadırlar.

Boş Bloklar Nasıl Oluşmaktadırlar?

Tabloya gelen transaction'lar datafile'lara kayıt ekledikçe bloklar bunlara göre arka arkaya düzenlenirler. Bu düzenleme sırasında bazı bloklar silinip, tabloya yeni ve daha büyük kayıtlar geldiğinde bu bloklar kullanılamazlar. Bu bloklar kullanılamamalarına rağmen boş durumdadırlar. Tablonun bu parçalanmış durumu hem harcanmış disk alanına hemde veritabanında performans kaybına yol açmaktadır.

Nasıl Düzeltililir?

Bu durumu düzeltmek için "online segment shrink"  işlemi gerçekleştirilir. Bu işlem ile boş alanlar birleştirilir ve kayıtların yazılacağı blok sınırını düşürür. Yani aynı extent içine daha fazla kayıt eklenebilir, daha fazla yer kazanılır.

Boş Alanlar Nasıl Bulunur?

Kullanılamayan boş alanları bulmak için "Segment Advisor" kullanılır. Bu araç hem Enterprise Manager'dan, hem veritabanından çalıştırılabilinir. Segment Advisor daha önceden çalıştıysa aşağıdaki sorgu bize Segment Advisor'ın bakıp bulduğu tablolardan hangisinde ne kadar yer kazanılabileceği ya da o tablolarda ne yapılması gerektiğini gösterir.

 SELECT segment_name,  
       round(allocated_space/1024/1024,1) alloc_mb,  
       round( used_space/1024/1024, 1 ) used_mb,  
         round( reclaimable_space/1024/1024) reclaim_mb,  
         round(reclaimable_space/allocated_space*100,0) pctsave,  
       recommendations  
    FROM TABLE(dbms_space.asa_recommendations())  
   where segment_owner = user  

Bir Tablespace'de Bulunan Tablo ve Index'ler İçin Boş Bloklar Var Mıdır?

Bu procedure'umuzu Toad'da DBMS Output açık olarak çalıştırırsak bize belirli bir tablespace'deki tablo ve index'lerde bulunabilecek boş bloklarla ilgili bilgi verebilir.


DECLARE  
  v_total_blocks  NUMBER;  
  v_total_bytes  NUMBER;  
  v_unused_blocks NUMBER;  
  v_unused_bytes  NUMBER;  
  v_file_id    NUMBER;  
  v_block_id    NUMBER;  
  v_last_block   NUMBER;  
  v_used      NUMBER;  
  v_owner     VARCHAR2(12);  
  v_segment    VARCHAR2(80);  
  v_type      CHAR(1);  
   
  CURSOR index_c is  
  SELECT owner, index_name  
   FROM sys.dba_indexes  
   WHERE tablespace_name = upper('&ts_name');  
   
  CURSOR table_c is  
  SELECT owner, table_name  
   FROM sys.dba_tables  
   WHERE tablespace_name = upper('&ts_name');  
   
 BEGIN  
  DBMS_OUTPUT.ENABLE(100000);  
  v_type := '&type';  
  IF (v_type = 'i' or v_type = 'I') THEN  
    OPEN index_c;  
    FETCH index_c into v_owner, v_segment;  
    WHILE index_c%FOUND LOOP  
       --  
       DBMS_SPACE.UNUSED_SPACE(v_owner, v_segment, 'INDEX', v_total_blocks, v_total_bytes,  
                   v_unused_blocks, v_unused_bytes, v_file_id, v_block_id, v_last_block);  
       --  
       DBMS_OUTPUT.PUT_LINE(CHR(10));  
       DBMS_OUTPUT.PUT_LINE('Index Name          = '||v_segment);  
       DBMS_OUTPUT.PUT_LINE('Total Blocks         = '||v_total_blocks);  
       DBMS_OUTPUT.PUT_LINE('Total Bytes         = '||v_total_bytes);  
       DBMS_OUTPUT.PUT_LINE('Unused Blocks        = '||v_unused_blocks);  
       DBMS_OUTPUT.PUT_LINE('Unused Bytes         = '||v_unused_bytes);  
       v_used := v_total_blocks - v_unused_blocks;  
       DBMS_OUTPUT.PUT_LINE('Used Blocks         = '||v_used);  
       v_used := v_total_bytes - v_unused_bytes;  
       DBMS_OUTPUT.PUT_LINE('Used Bytes          = '||v_used);  
       DBMS_OUTPUT.PUT_LINE('Last used extents file id  = '||v_file_id);  
       DBMS_OUTPUT.PUT_LINE('Last used extents block id  = '||v_block_id);  
       DBMS_OUTPUT.PUT_LINE('Last used block       = '||v_last_block);  
       fetch index_c into v_owner, v_segment;  
    END LOOP;  
    CLOSE index_c;  
  ELSIF (v_type = 't' or v_type = 'T') THEN  
   OPEN table_c;  
     FETCH table_c into v_owner, v_segment;  
     WHILE table_c%FOUND LOOP  
       --  
       DBMS_SPACE.UNUSED_SPACE(v_owner, v_segment, 'TABLE', v_total_blocks, v_total_bytes,  
                   v_unused_blocks, v_unused_bytes, v_file_id, v_block_id, v_last_block);  
       --  
       v_used := v_total_bytes - v_unused_bytes;  
       DBMS_OUTPUT.PUT_LINE(CHR(10));  
       DBMS_OUTPUT.PUT_LINE('Table Name          = '||v_segment);  
       DBMS_OUTPUT.PUT_LINE('Total Blocks         = '||v_total_blocks);  
       DBMS_OUTPUT.PUT_LINE('Total Bytes         = '||v_total_bytes);  
       DBMS_OUTPUT.PUT_LINE('Unused Blocks        = '||v_unused_blocks);  
       DBMS_OUTPUT.PUT_LINE('Unused Bytes         = '||v_unused_bytes);  
       v_used := v_total_blocks - v_unused_blocks;  
       DBMS_OUTPUT.PUT_LINE('Used Blocks         = '||v_used);  
       v_used := v_total_bytes - v_unused_bytes;  
       DBMS_OUTPUT.PUT_LINE('Used Bytes          = '||v_used);  
       DBMS_OUTPUT.PUT_LINE('.  KBytes         = '||v_used/1024);  
       DBMS_OUTPUT.PUT_LINE('.  MBytes         = '||(v_used/1024)/1024);  
       DBMS_OUTPUT.PUT_LINE('Last used extents file id  = '||v_file_id);  
       DBMS_OUTPUT.PUT_LINE('Last used extents block id  = '||v_block_id);  
       DBMS_OUTPUT.PUT_LINE('Last used block       = '||v_last_block);  
       fetch table_c into v_owner, v_segment;  
    END LOOP;  
    CLOSE table_c;  
  END IF;  
 END;  
 /  


Segment Advisor Nedir?

"Automatic Segment Advisor" bir maintanence task'idir. Yani maintenance aralıklarında çalışan bir işlemdir. Bu işlem bazı veritabanı objelerini inceler. Bu objeler seçilmeden önce belirli kriterlere bakılır.

Bu kriterler:
-Tablespace'in belirli bir seviyeyi geçmiş olması
-Çok fazla aktif olan segment'ler(Yukarıda belirttiğimiz gibi update,delete,insert ifadeleri çok gerçekleşen tablolar)
-En fazla büyüyen segment'ler

Buna göre seçilen objeler maintenance aralıkları boyunca incelenirler.

Elle Segment Advisor'ı Çalıştırmak:

Segment Advisor maintenance aralıklıklarında otomatik olarak çalıştırdığımız için bazen elle çalıştırmamız gerekebilir. Merak ettiğimiz bir tablespace'i incelemek istiyorsak, elle çalıştırmamız gerekir.

Elle çalıştırabilmek için 2 yöntem vardır. Bir tanesi "Enterprise Manager"'dan "Segment Advisor Wizard"'a gidip istediğimiz tablespace'i veya tabloyu seçip "Run Segment Advisor"'ı seçebiliriz. Diğer yöntem de PL\SQL job'ı çalıştırmak olacaktır.

PL\SQL ile Segment Advisor çalıştırılması örneği:

 create or replace procedure segment_advisor_calistirmak  
   authid current_user  
  as  
    obj_id number;  
   begin  
    dbms_advisor.create_task (  
     advisor_name   => 'Segment Advisor',  
     task_name    => 'segment_advisor' );  
    
    dbms_advisor.create_object (  
     task_name    => 'segment_advisor',  
     object_type   => 'TABLE',  
     attr1      => berke,  --Kullanıcı ismi
     attr2      => 'employees',   --Tablo ismi
     attr3      => NULL,  
     attr4      => NULL,  
     attr5      => NULL,  
     object_id    => obj_id);  
    
    dbms_advisor.set_task_parameter(  
     task_name    => 'segment_advisor',  
     parameter    => 'recommend_all',  
     value      => 'TRUE');  
    
    dbms_advisor.execute_task('segment_advisor');  
   end;  
   /  

Yukarıdaki örnekte PL\SQL ile bir procedure oluşturmuş oluyoruz. Bu procedure'de belirli bir tablo ismi ve kullanıcı ismi vermiş bulunuyoruz. Bu şekilde her seferinde bu procedure'ı çağırdığımızda aynı tabloyla ilgili segment tavsiyeleri almış oluruz. Bu procedure'ı parametreli hale getirirsek de istediğimiz tabloyu veya tablespace'i inceleyecek hale getirmiş oluruz. Sonrasında aşağıdaki gibi çalıştırabiliriz.

Not: segment_advisor_calistirmak yukarıdaki prosedürümüzün adıdır.

exec segment_advisor_calistirmak;  

Bu procedure çalıştırıldıktan sonra bunların sonuçlarını görmek için 3 tane yöntem vardır.

-Enterprise Manager ile
-DBA_ADVISOR_* view'ları ile
-DBMS_SPACE.ASA_RECOMMANDATIONS prosedürünü

Shrink Etme İfadesi Nedir?

Tablolar için genel olarak küçültme ifadesini vermeden önce o tablo için "row movement" özelliği açık olmalıdır.

 "alter table tablo_adı enable row movement;"  

Sonrasında ise

"alter table tablo_adı shrink space compact;"  

ve

  "alter table tablo_adı shrink space;"  


Shrink İşleminin Sonuçlarını Nasıl Görebilirim?

Shrink edeceğimiz dosyanın boyutunu görmek için dba_tables tablosu sorgulanır.

 select blocks from dba_tables where table_name='TABLO_ADI';  

Bu şekilde tablomuzun şu an kapsadığı boyutu görebiliriz.

Shrink işlemini gerçekleştirdikten sonra da aşağıdaki gibi şu anki istatistikleri görebiliriz.

 analyze table tablo_adı compute statistics;  
   
 analyze table tablo_adı estimate statistics sample 10 percent;

O istatistikleri güncelledikten sonra tekrar aynı sorguyu çektiğimizde tablonun küçülme seviyesini görebiliriz.

 select blocks from dba_tables where table_name='TABLO_ADI';  

Buna istinaden dba_segments'den tablo boyutunu da inceleyebiliriz.

select bytes/1024/1024 as 'MB' from dba_segments where segment_name='tablo_adı';


Not: Ayrıca buradaki yazımıza da bakabiliriz. (Günlük Kontroller - Tablespace)


Referans:
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:54178027703899
http://docs.oracle.com/cd/B28359_01/server.111/b28310/schema003.htm#ADMIN11608
http://myorastuff.blogspot.com.tr/2008/07/how-do-we-reclaim-wasted-space-in-table.html
http://www.bestremotedba.com/2010/05/11/reclaim-wasted-space-in-10g/

Hiç yorum yok:

Yorum Gönder