Monday, June 29, 2009

RAID disk sürücüleri hakkında

ASM de Disk gruplaması aşağıdaki yapıda oluyor.

NORMAL REDUNDANCY - İki disk eş zamanlı çalışıyor.
HIGH REDUNDANCY -Üç disk eş zamanlı çalışıyor.
EXTERNAL REDUNDANCY - aynalama kullanılmıyor. RAID -1 kullanmak mantıklı.

Aslında yukarıdaki yapıya bakarsak olay verilerimizi tek bir yerde tutmayalım. Fiziksel bir sorun olduğunda ikincisinden devam etmek .
RAID için buradan ayrıntılı bilgi alabilirsiniz. Ayrıca Veri güvenliğinin nasıl yapıldığına da bir bakış açısı kazanabiliriz.

PARAMETRE DOSYALARıNıN KONUMUNU ÖĞRENMEK

--parametre dosyalarının konumunu öğrenmek için aşağıdaki sorgu işinize yarayabilir.
--ben burada dizin ile başlayanlara göre bir kırılım yaptım.

SELECT name,value,display_value
FROM sys.v_$parameter where value like '/%'


spfile
control_files
background_dump_dest
user_dump_dest
core_dump_dest
audit_file_dest
dg_broker_config_file1
dg_broker_config_file2

Friday, June 26, 2009

BLOCK CHANGE TRACKING

BLOCK CHANGE TRACKING (BCT)database'deki değişkliklerin yapıldığı block'ları tutan dosyadır. RMAN ile incremantal (artalan) yedekleme işlemi yaparken yapılan değilişliklerin hangi blocklarda yada nerelerde olduğunu tespit etmek için BTC dosyasına bakıyor. Bunun bize sağladığı avantaj ise bütün verileri tek tek tarayarak zaman kaybetmekten ise buradan bakıp ilgili blockları yedeklemek.
Bu özelliğin aktif olup olmadığını görmek için aşağıdaki sorguyu kullanabiliriz.
SELECT filename, status, BYTES
FROM v$block_change_tracking;

Enable yapmak için aşağıdaki komuyu kullanabiliriz. Bu işlemleri yapak için SYS user'ı ile bağlanmanız gerekiyor.
ALTER DATABASE ENABLE BLOCK CHANGE TRACKING
--dosyayı ben belirliyorum.
USING FILE 'c:\oracle\product\flash_recovery_area\ORABASE\bctf01.log';

disable yapmak için ise
ALTER DATABASE DISABLE BLOCK CHANGE TRACKING;
disable yaptığınızda dosyanız silinecektir.

dosyanın adını ve konumunu değiştirmek için MOUNT moda geçtikten sonra aşağıdaki işlemi yapmak gerekiyor.Aksi halde aşağıdaki hataları alırsınız.

ORA-01511: günlük/veri dosyalarını adlandırmada hata
ORA-19771: veritabanı açıkken değişiklik izleme dosyası yeniden adlandırılamaz.

ALTER DATABASE RENAME FILE
'c:\oracle\product\flash_recovery_area\ORABASE\bctf01.log'
TO 'c:\oracle\product\flash_recovery_area\ORABASE\new_name.log';

Eğer siz derseniz benim database'im kritik öyle canım istedikce Mount moda alamam. Ve bu dosyanın (bctf01.log) konumunu ve adını değiştirmek istiyorum o zaman önce disable yap sonra enable yaparkende yeni FILENAME ver.

BCT yi aktif duruma getirip sistemdeki değişiklikleri takip ediyor ve belirlediğimiz dosyaya(bctf01.log) kaydediyoruz. Sonra belirli sebeblerden pasif (enable) yapıp sonra tekrar aktif yaparsanız belirlediğimiz dosya yeniden oluşturulacaktır. İçerisi boşalacaktır.

readonly tablespace'de RMAN ile incremantal backup alırken BLOCK CHANGE TRACKING i kullanmaz. Readyonly bir yapıda zaten bir değişiklik olmayacağı için BCT yi kullanmak performans kaybına neden olacaktır
.


kaynak : http://www.oracle.com/technology/oramag/oracle/04-nov/o64rman.html

DATABASE STATUS

VeriTabanımız hakkında temel bilgileri almak için aşağıdaki sorguyu kullanabiliriz.

select name,open_mode,log_mode,platform_name,CURRENT_SCN from v$database
Burada

name : Databasenin adını bize veriyor.
db_unique_name: Databasenin benzersiz adi RMAN ile bağlanırken bunu kullanıyorsunuz.
open_mode : Hangi modda açildiğini gösteriyor. WRITE -READ
Log_mode : ARCHIVE mi yoksa NOARCHIVE modda mı olğunu görebiliriz.
platform_name:Oraclenin kurulduğu işletim sistemi hakkında bize bilgi veriyor.
current_scn : En son SCN numarasını verir Flashback işleminde bu numarayı kullanarak recovery yapıyoruz.

BOZUK BLOCK'LARIN BELİRLENMESİ

Database'de bozuk olan block'ların belirlemek için
select * from V$DATABASE_BLOCK_CORRUPTION
sorgusunu kullanabiliriz.
örneğin bir tablo yaratalım ve içerisini dolduralım.
--boş tablomuzu yaratalım
create table bozuk_deneme as select * from user_objects where 1=3
--ekleme işlemini yapalım.
insert into bozuk_deneme select * from user_objects

select * from bozuk_deneme;
bozuk bir block'ta olan tabloya erişmeye çalışdığımızda aşağıdaki hatayı alırız.
ORA-01578: ORACLE data block corrupted (file # 6, block # 256)
ORA-01110: data file 6: ‘/u01/app/oracle/oradata/orcl/bozuk_dosya.dbf’
aklımıza ilk gelen durum burada RMAN ile bağlanarak aşağıdaki sorguyu çalıştırmaktır.
BLOCKRECOVER DATAFILE 6 BLOCK 256;
eger bunun ile bir çözum bulamaz isek datafileden dönme yapılmalıdır. Ilgili datafile recovery yapılabilir.

--arkamızda tablo bırakmalım ortalık tablo ile dolmasın.
drop table bozuk_deneme

kaynak :http://www.sc.ehu.es/siwebso/KZCC/Oracle_10g_Documentacion/server.101/b10734/rcmrecov.htm#1006579

Monday, June 22, 2009

BÜTÜN PARTITION'LARIN COUNT'UNU BİR SEFERDE ALMA

Bir tabloda bulunan partitionların count'larını teker teker almaktansa hepsini bir seferde alabiliriz. bunun için yapıalcak islem basit.

öncelik ile procederure yaratalım.

CREATE OR REPLACE PROCEDURE part_count (pin_table_name IN VARCHAR2)
IS
CURSOR s1
IS
SELECT /*+ parallel(t,8) */
partition_name AS v_part_name
FROM user_tab_partitions t
WHERE table_name = pin_table_name;

rec_s1 s1%ROWTYPE;
v_table_name VARCHAR2 (30);
v_dynsql VARCHAR2 (200);
v_sonuc VARCHAR2 (200);
BEGIN
v_table_name := pin_table_name;
OPEN s1;
LOOP
FETCH s1
INTO rec_s1.v_part_name;
EXIT WHEN s1%NOTFOUND;
v_dynsql :=
'select /*+ parallel(t,8) */ count(1) as v_sonuc from '
|| v_table_name
|| ' partition ('
|| rec_s1.v_part_name
|| ') t';

EXECUTE IMMEDIATE v_dynsql
INTO v_sonuc;

DBMS_OUTPUT.put_line (v_dynsql || ' --' || v_sonuc);
--DBMS_OUTPUT.put_line (v_sonuc);
-- DBMS_OUTPUT.put_line ('DENEME');
END LOOP;

CLOSE s1;
END;
/
--partitionlu yapıya sahip bir tablomuz olması gerekiyor. Bunuda hemen yaratalım.

create table part_deneme

(OWNER VARCHAR2(30 BYTE) NOT NULL,

OBJECT_NAME VARCHAR2(30 BYTE) NOT NULL,

SUBOBJECT_NAME VARCHAR2(30 BYTE),

OBJECT_ID NUMBER NOT NULL,

DATA_OBJECT_ID NUMBER,

OBJECT_TYPE VARCHAR2(19 BYTE),

CREATED DATE NOT NULL,

LAST_DDL_TIME DATE NOT NULL,

TIMESTAMP VARCHAR2(19 BYTE),

STATUS VARCHAR2(7 BYTE),

TEMPORARY VARCHAR2(1 BYTE),

GENERATED VARCHAR2(1 BYTE),

SECONDARY VARCHAR2(1 BYTE)

)

partition by range (object_id)

(partition part_01 values less than (20000) tablespace users,

partition part_02 values less than (40000) tablespace example,

partition part_03 values less than (60000) tablespace users,

partition part_04 values less than (maxvalue) tablespace users)

tabloyu ayrattık şimdi içine verileri ekleyelim.

insert into part_deneme select * from all_objects

--sonra bu nu çalıştıralım.
DECLARE
PIN_TABLE_NAME VARCHAR2(200);

BEGIN
PIN_TABLE_NAME := NULL;

HR.PART_COUNT ('PART_DENEME');
COMMIT;
END;

Sunday, June 21, 2009

ORACLE İLE İŞLETİM SİSTEMİ DOSYALARINI SİLME

Oracle userları ile işletim sistemi dosyalarını silebilirsiniz. Bunun için yetkiniz olması gerekiyor. SYS user ı ile bağlandığınız zaman herhangibi bir sorun ile karşılaşmıyorsunuz. Öncelik ile directories (dizin) yaratmalısınız. sonra o dizinin altındakileri siliyorsunuz.örneğin direck dizin oalrak c:\ verirseniz C dizini içerisindeki herşeyi silebilirsiniz.

--önce dizin yaratalım.

create directory deneme as 'c:\'

--silme işlemini yapalım.

exec dbms_backup_restore.deletefile('C:\Documents and Settings\Administrator\Desktop\deneme.txt');

Tuesday, June 16, 2009

ORACLE DIRECTORIES (DİZİNLER)

Directories(dizin) yaratılması ve bu diznlere hak vermek için aşağıdaki adımları izleyebilirsiniz.

--aşağıdaki işlemleri SYS userı ile yapmanız gerekiyor.
--hr kullanıcısına dba_directories için erişim yetkisi veriyoruz.
GRANT SELECT ON dba_directories TO hr
--directories (dizin oluşturalım)
CREATE DIRECTORY deneme_directories AS 'c:\oracle\dosyalarim'
--oluşturduğumuz dizin için HR kullanıcısına okuma yetkisi verelim.
GRANT READ ON DIRECTORY deneme_directories TO hr
--oluşturduğumuz dizin için HR kullanıcısına yazma yetkisi verelim.
GRANT WRITE ON DIRECTORY deneme_directories TO hr
--iki yetkiyi birden vermek için
grant read,write on directory deneme_directories to hr;

--yetkileri geri almak için
REVOKE READ ON DIRECTORY deneme_directories FROM hr;
REVOKE WRITE ON DIRECTORY deneme_directories FROM hr;

VİRGÜL İLE AYRILMIŞ DOSYADAN KAYITLARI TABLOYA AKTARMA

--öncelik ile yükleme yapacağımız tabloyu yaratalım.

create table kisiler(adi varchar2(30),
soyadi varchar2(30),
yasi number);

--Küçük bir not ekleyelim hemen araya. burada directory  adını verirken buyuk harf ile vermeyi

--unutmayalım. dosyadan okuduğu için buyuk hart vermeniz gerekecektir.

--paketimizi yaratalım.

CREATE OR REPLACE PROCEDURE dosyadan_yukleme
AS
v_line VARCHAR2 (2000); -- dosyadan okunacak her bir satır
v_file UTL_FILE.file_type; -- Verilerin olduğu dosya
v_dir VARCHAR2 (250); -- dosyanın bulunduğu dizin
v_filename VARCHAR2 (50); -- dosyamızın adı
v_1st_virgul NUMBER; --ilk virgulun olduğu yer
v_2nd_virgul NUMBER; --ikinci virgülün olduğu yer
v_adi VARCHAR2(30); --alanlarımız için değişkenler ADI
v_soyadi VARCHAR2 (30); --alanlarımız için değişkenler SOYADI
v_yasi NUMBER; --alanlarımız için değişkenler YASI
BEGIN
v_dir := 'dosya_yolum';
v_filename := 'kisiler.txt';
v_file := UTL_FILE.fopen (v_dir, 'kisiler.txt', 'r',1000);

-- --------------------------------------------------------
--DOSYA SONUNA GELENE KADAR OKU
-- --------------------------------------------------------
LOOP
BEGIN
UTL_FILE.get_line (v_file, v_line);
EXCEPTION
WHEN NO_DATA_FOUND
THEN
EXIT;
END;

v_1st_virgul := INSTR (v_line, ',', 1, 1);
v_2nd_virgul := INSTR (v_line, ',', 1, 2);
v_adi := SUBSTR (v_line, 1, v_1st_virgul - 1);
v_soyadi :=
SUBSTR (v_line, v_1st_virgul + 1, v_2nd_virgul - v_1st_virgul - 1);
v_yasi := SUBSTR (v_line, v_2nd_virgul + 1);
DBMS_OUTPUT.put_line (v_adi|| ' - ' || v_soyadi || ' - ' || v_yasi);

-- ------------------------------------------
-- Kayıtları oluşturduğumuz tabloya eklemeyi yapıyoruz.
-- ------------------------------------------
INSERT INTO kisiler
VALUES (upper(v_adi), UPPER (v_soyadi), v_yasi);
END LOOP;

UTL_FILE.fclose (v_file);
COMMIT;
END;
/

--dosyamda aşağıdaki gibi kayıtlar var.
--ali,ates,12
--ali,ateş,25
--nurullah,ünlü,24
--akın,yalçın,30



BEGIN
DOSYADAN_YUKLEME;
COMMIT;
END;

BÜYÜK TABLOLARDA DELETE İŞLEMİ

Büyük tabloları silerken aşağıdaki yöntemi kullanırsanız UNDO TABLESPCADE'DEN Yer kazancı sağlarsınız ama performans acısından biraz geç bitecektir sorgunuz.
Nasıl çalıştığına kısaca değinmek gerekir ise undo segment commit yapılana kadar bütün tabloyu yada update ve delete işlemine maruz kalan kayıtları tutar. Buda bizim için büyük boyutlu tabloları silmede sorun oluşturur. Aşağıdaki yöntemde ise 1000 er 1000 er commit işlemi yaprak undo segment de yer kazancı sağlar. Bu değeri değiştirebiliriz. Tercih sizin.
Delete yönteminden daha iyi olan yöntem önce istenilen satırlar için tablonun yedeğini alma sonra truncate edip tablonun ismini değiştirmektir. Truncate delete denebilir (Aslında böyle bir isim üretmek lazım.) Bu yöntem veri ambarlarında (data warehouse) kullanılıyor.


SET timing on
--ne kadar sürede çalıştığını görek için bunu ekliyoruz.
DECLARE
v_count NUMBER := 0;
toplam NUMBER := 0;
--silinecek veriler için curcor tanımlayalım.
CURSOR del_record_cur
IS
SELECT ROWID
FROM sil_deneme;
--where ile istediğimiz koşulu burada girebiliriz.
--koşulsuz silmek biraz saçma olacaktır. TRUNCATE etmek gerekir.
BEGIN
FOR rec IN del_record_cur
LOOP
DELETE FROM sil_deneme
WHERE ROWID = rec.ROWID;

toplam := toplam + 1;
v_COUNT := v_COUNT + 1;
--burada kaç kayıt silindikten sonra commit yapılacağına kendiniz karar veriniz.
IF (v_COUNT >= 1000)
THEN
COMMIT;
v_COUNT := 0;
END IF;
END LOOP;

COMMIT;
DBMS_OUTPUT.put_line ( 'sil_deneme tablosundan '
|| toplam
|| ' kayıt silinmiştir'
);
END;
/

çalışma sürelerini değerlendirirsek.

sil_deneme tablosundan 928161 kayıt silinmiştir
Elapsed: 00:00:50.28
//////////////////////////////////////////////////
delete from sil_deneme
928161 rows deleted.
Elapsed: 00:00:25.18



Bazı arkadaşlarımız data warehouse'da delete işlemine kesinlikle karşı çıkacaklardır. Haklılarda. Ama şu şekilde bir durum oluştuğunda ne olacak.
400.000.000 kayıtlı bir tablom var vebu tabloda 10 milyon kayıt yanlış girilmiş. Bende bu 10 milyon kaydı silmeliyim. 10 milyon kayıt için tabloyu swap'lamakda
o kadar akılcı gelmiyor bana bu şekilde parça parça delete işlemi yapılabilinir.
bir diğer yöntem ise ki bu bence daha güzel.
DECLARE
BEGIN
--10 milyon kaydi birer milyon birer milyon silecegimiz için 10 defa döngüye soktum
--Bu örneği diğer örnekten hızlı yapan yönu ile birer birer silmesi değil toplu olarak silmesidir.
--bu esnada paralellik hint'i verilerecek
--ciddi zaman kazancı sağlayabilirsiniz.
FOR i IN 1 .. 10
LOOP
DELETE FROM delete_deneme
WHERE acoount_id > 345000
--silinecek olan kayıtları belirledikten sonra rownum ile birer milyonluk siliyorum.
AND ROWNUM <1000000
--her 1 milyon kayitta bir commit yapiyorum.
--undo segment dolmuyor :))

COMMIT;
END LOOP;
--bu commit de benden olsun
COMMIT;
END;

Monday, June 15, 2009

DELETE İŞLEMİ HAKKINDA BİRKAÇ ÖRNEK

--kendimize işlemlerimizde kullanmak için Oracle Dictionary'lerinden bir tablo oluşturalım
CREATE TABLE DELETE_DENEME AS SELECT * FROM user_objects

--bakalım tablomuz oluşmuş mu ve içerisinde ne gibi kayıtlar var
--burada object_type alanı delete işleminde seçmeyi göstermek için uygun bir sütün.
select /*+ parallel(t,8) */ * from delete_deneme t

--tablomun bir yedeğini oluşturuyorum. Her seferinde Dictionary'e gitmekten iyidir.
create table delete_deneme_yedek as select * from delete_deneme
--TABLOYU KOMPLE SİLMEK İÇİN
--ilk delete örneğini yapalım. burada direk siliyoruz.Araya table demeye gerek yok.
--burada delete [silmek istediğimiz tablonun adi]
delete delete_deneme
--Sildikten sonra kaydetmeyi yapalım.
commit;
--tablomuzu yeniden dolduralım
insert into delete_deneme select * from delete_deneme_yedek
--belirli bir koşula uyan kayıtları silmek için.
delete FROM delete_deneme where object_type='TABLE'
commit;
--tablomuzu komple boşaltım yeniden dolduralım.Kullanıma hazır duruma getirelim.
truncate table delete_deneme
insert into delete_deneme select * from delete_deneme_yedek
--alt sorgu yazarakta delete işlemi yapabiliriz.
delete from delete_deneme where delete_deneme.object_id in (select d.object_id from delete_deneme d, delete_deneme_yedek y where y.object_type='TABLE' and d.object_type=y.object_type )
--Biraz karısık bir sorgu gibi oldu. tablo isimleri birbirine çok benzedi sanki.
--son olarak tablolarımız silelim.
--arkamızda pisliğimiz kalmasın.
drop table delete_deneme
drop table delete_deneme_yedek

SORGULARIN ÇALIŞMA SÜRESİ

Çalıştırdığımız sql sorgusunun ne kadar sürede sonlandığı bilmek isteyebiliriz. Performans değerlendirmesi için bu bilgi bize gerekli olabilir. zaten bircoğumuzda çeşitli forumlarda
1 row selected.
Elapsed: 00:00:00.04
gibi bir çıktıyı en altta görebiliriz. Bu çıktıyı bizde almak için aşağıdaki komutu sorgunun başına eklemeniz yeterli olacaktır.

set timing on
select * from dual;


Sunday, June 14, 2009

PARTITION SUBPARTITION BÖLÜM 2

ORACLE 11g ile birlikte partition methotlarına yenileri eklendi. Bunlar
  • Range-Hash (available since 8i)
  • Range-List (available since 9i)
  • Range-Range
  • List-Range
  • List-Hash
  • List-List
Şu anda 11g makinamda kurulu olmadığı için bunlar için örnek kod yazamayacağim ama aşığıdaki sitede çok güzel örnekler mevcut.
http://www.oracle-base.com/articles/11g/PartitioningEnhancements_11gR1.php#virtual_column_based_partitioning
COMPRESS PARTITION
partition bazılı sıkıştırma (compress) işlemi yapabiliriz. Bir tabloyu compress yaratabiliriz ama bu demek değildir ki bütün partitionları compress olacak. Kendi belirlediğimiz herhangi birtanesi compress yapabiliriz.

--partition truncate etmek icin
alter table range_part truncate partition part_02


CREATE TABLE range_compress_part

( owner VARCHAR2(30 BYTE) NOT NULL,

object_name VARCHAR2(30 BYTE) NOT NULL,

subobject_name VARCHAR2(30 BYTE),

object_id NUMBER NOT NULL,

data_object_id NUMBER,

object_type VARCHAR2(19 BYTE),

created DATE NOT NULL,

last_ddl_time DATE NOT NULL,

TIMESTAMP VARCHAR2(19 BYTE),

status VARCHAR2(7 BYTE),

TEMPORARY VARCHAR2(1 BYTE),

GENERATED VARCHAR2(1 BYTE),

secondary VARCHAR2(1 BYTE)

)

compress

PARTITION BY RANGE (object_id)

(PARTITION part_01 VALUES LESS THAN (20000),

--kendi belirlediğim bir partition'u nocompress moda çekiyorum

PARTITION part_02 VALUES LESS THAN (40000) nocompress tablespace users ,

pARTITION part_03 VALUES LESS THAN (60000) tablespace example,

PARTITION part_04 VALUES LESS THAN (MAXVALUE) )

--yaratmış olduğumuz partitionlar ile ilgili ayrıntılı bilgi için aşağıdaki sorgu işimizi görecektir.

--burada yaratmış olduğumuz partitionların ayrıntılı bilgilerini alırız.

select table_name,partition_name,high_value,tablespace_name,compression from user_tab_partitions where lower(table_name)='range_part'

--kullancının sahip olduğu tablespaceleri görerek bunlardan birsisini seçebiliriz.

select * from user_tablespaces

--move partition

select * from user_tab_partitions where table_name='RANGE_PART'

alter table range_part move partition part_01 tablespace example

--move subpartition

select * from user_tab_subpartitions where table_name='RANGE_HASH_PART'

ALTER TABLE RANGE_HASH_PART move subPARTITION PART_004_SP3 tablespace example

--subpartition'ların adlarını ve tablespacelerini değiştirmek için için.

alter table RANGE_HASH_PART

set subpartition template (

subpartition sp1 tablespace users,

subpartition sp2 tablespace users,

subpartition sp3 tablespace users,

subpartition sp4 tablespace users

)

--add partition (partition eklemek için)

select * from user_tab_partitions where table_name='RANGE_PART'

--maxvalue oldugu için son partitionu silmek gerekiyor.Bu sebebten dolayı silip yeniden yaratıyoruz.

alter table range_part drop partition part_04

alter table range_part add partition part_04 values less than (70000)

--partition isimlerini değiştirmek için aşağıdaki komur işinizi görecektir.

alter table range_part rename partition part_01 to ilk_part

select * from user_tab_partitions where table_name='RANGE_PART'

PARTITION VE SUBPARTITION

Bu yazımda Partition’lar hakkın da bildiklerimi sizin ile paylaşmaya çalışacağım. Öncelik ile ön bilgi olması açısından Partition’lar ile ilgili olan Oracle View’leri size aktarayım. Bunlar DBA, ALL, & USERS olmak üzere 3 farklı aşamada olabilirler.

DBA

USER

ALL

dba_tab_cols

user_tab_cols

all_tab_cols

dba_ind_partitions

user_ind_partitions

all_ind_partitions

dba_ind_subpartitions

user_ind_subpartitions

all_ind_subpartitions

dba_lob_partitions

user_lob_partitions

all_lob_partitions

dba_lob_subpartitions

user_lob_subpartitions

all_lob_subpartitions

dba_subpartition_templates

user_subpartition_templates

all_subpartition_templates

dba_subpart_col_statistics

user_subpart_col_statistics

all_subpart_col_statistics

dba_subpart_histograms

user_subpart_histograms

all_subpart_histograms

dba_subpart_key_columns

user_subpart_key_columns

all_subpart_key_columns

dba_tab_partitions

user_tab_partitions

all_tab_partitions

dba_tab_subpartitions

user_tab_subpartitions

all_tab_subpartitions

Partitionlar ile ilgili Dictionary Object’lerin nerede olacağını gösterdikten sonra partition türlerini belirleyelim.

· Range partition (belirli bir limit aralığı)

· Hash partition (Hash fonksiyonunun ürettiği sonuca göre)

· List partition (belirli bir liste yapılarak o lste bazlı partition)

· Range-hash partition (partition range subpartition hash )

· Range-list partition (partition range subpartition list)

Partitionların Tableapaceler üzerindeki dağılıma bakacak olursak. Oracle bu konuda bize çok büyük esneklikler sağlıyor. İstediğimiz Partition’u istediğimiz Tablespace’ye taşımamıza yada istediğimiz yerde yaratmamıza izin veriyor. Aslında böylede olması gerekiyor çünkü partition ve subpartition yapısını kullanmak zorunda isek bunun sebebi tablolarımızın çok büyük boyutlu olması. Tabloyu tek bir tablespace’ye hapsetmek bu durumda mantıklı değil zaten. Tablespace’de yer kalmadığı zaman partition yada tabloları başka tablespace’lere taşıyarak geçici olarak da olsa yer sorununa bir çözüm getirebiliriz.

Partition’lu tablo yaratırken örnek tabloları ALL_OBJECTS ile dolduracağım. Nede olsa herkesin database’sinde mevcut. :))

RANGE PARTITION

create table range_part

(OWNER VARCHAR2(30 BYTE) NOT NULL,

OBJECT_NAME VARCHAR2(30 BYTE) NOT NULL,

SUBOBJECT_NAME VARCHAR2(30 BYTE),

OBJECT_ID NUMBER NOT NULL,

DATA_OBJECT_ID NUMBER,

OBJECT_TYPE VARCHAR2(19 BYTE),

CREATED DATE NOT NULL,

LAST_DDL_TIME DATE NOT NULL,

TIMESTAMP VARCHAR2(19 BYTE),

STATUS VARCHAR2(7 BYTE),

TEMPORARY VARCHAR2(1 BYTE),

GENERATED VARCHAR2(1 BYTE),

SECONDARY VARCHAR2(1 BYTE)

)

partition by range (object_id)

(partition part_01 values less than (20000) tablespace users,

partition part_02 values less than (40000) tablespace example,

partition part_03 values less than (60000) tablespace users,

partition part_04 values less than (maxvalue) tablespace users)

Burada partition yaratırken hata almamak için bu yöntemi kullanıyorum. Böylece gelen her kayıt mutlaka bir partition ile eşleşecektir.

Tablomu aşağıda sorgu ile dolduruyorum.

insert into range_part select * from all_objects

Bakalım partitionlarda kaçar kayıt var. Ayrıca aşağıdaki sorgu örneğinde partition bazlı tablo erişimine örnek var.

select count(*) from range_part partition (part_01) --15432

select count(*) from range_part partition (part_02) --19977

select count(*) from range_part partition (part_03) --8356

select count(*) from range_part partition (part_04) --0

Tablodaki toplam kayıta bakarsak partitionların toplamını bize verecektir.

select count(*) from range_part –43765

HASH PARTITION

create table hash_part

(OWNER VARCHAR2(30 BYTE) NOT NULL,

OBJECT_NAME VARCHAR2(30 BYTE) NOT NULL,

SUBOBJECT_NAME VARCHAR2(30 BYTE),

OBJECT_ID NUMBER NOT NULL,

DATA_OBJECT_ID NUMBER,

OBJECT_TYPE VARCHAR2(19 BYTE),

CREATED DATE NOT NULL,

LAST_DDL_TIME DATE NOT NULL,

TIMESTAMP VARCHAR2(19 BYTE),

STATUS VARCHAR2(7 BYTE),

TEMPORARY VARCHAR2(1 BYTE),

GENERATED VARCHAR2(1 BYTE),

SECONDARY VARCHAR2(1 BYTE)

)

partition by hash (object_id)

partitions 4

store in (users,users,example,users);

yaratmış olduğumuz bu partitionların isimlerini öğrenmek için

select * from user_tab_partitions

sorgusunun sonucuna bakmak gerekir. Bu sorgu sonucunda user’a ait partition’ların hepsini bulabiliriz. Hatta hangi tabloya ait olduklarını ve hangi tablespace’de yer aldıklarını görebiliriz.

Sorgumuzu biraz güzelleştirelim

select * from user_tab_partitions where lower(table_name)='hash_part'

LIST PARTITION

create table list_part

(OWNER VARCHAR2(30 BYTE) NOT NULL,

OBJECT_NAME VARCHAR2(30 BYTE) NOT NULL,

SUBOBJECT_NAME VARCHAR2(30 BYTE),

OBJECT_ID NUMBER NOT NULL,

DATA_OBJECT_ID NUMBER,

OBJECT_TYPE VARCHAR2(19 BYTE),

CREATED DATE NOT NULL,

LAST_DDL_TIME DATE NOT NULL,

TIMESTAMP VARCHAR2(19 BYTE),

STATUS VARCHAR2(7 BYTE),

TEMPORARY VARCHAR2(1 BYTE),

GENERATED VARCHAR2(1 BYTE),

SECONDARY VARCHAR2(1 BYTE)

)

partition by list (object_type)

(partition list_01 values ('CONSUMER GROUP','TABLE SUBPARTITION','SEQUENCE','SCHEDULE','JAVA DATA','TABLE PARTITION'),

partition list_02 values ('PROCEDURE','OPERATOR','WINDOW','PACKAGE','PACKAGE BODY','LIBRARY'),

partition list_03 values ('PROGRAM','TYPE BODY','JAVA RESOURCE','XML SCHEMA','TRIGGER','JOB CLASS'),

partition list_04 values ('TABLE','SYNONYM','VIEW','FUNCTION','WINDOW GROUP','INDEXTYPE'),

partition list_05 values ('INDEX','TYPE','EVALUATION CONTEXT','JAVA CLASS'));

insert into list_part select * from all_objects

select distinct object_type from all_objects

Listede olması gerekenleri ekledim ama oracle bir şeye kızdı neden acaba??

ORA-14400: inserted partition key does not map to any partition

ORA-14400: eklenen bölüm anahtarI hiçbir bölümle eşleşmiyor

Aslinda bu hatayı almaması gerekir bütün olasılıkları tek tek denedim oluyor ama tabloyu bir seferde almadı.

Düzeltme : aynı işlemi scriptte herhangibi bir değişiklik yapmadan denedim çalıştı. Benim TOAD kafayı yedi herhalde.

insert into list_part select * from all_objects where object_type='CONSUMER

GROUP'

Madem * ile yemiyorsun bende tek tek veririm sana buda çalışmasın göreyim seni :))

insert into list_part select * from all_objects

where object_type in ('CONSUMER GROUP','TABLE SUBPARTITION','SEQUENCE','SCHEDULE','JAVA DATA','TABLE PARTITION','PROCEDURE','OPERATOR','WINDOW','PACKAGE','PACKAGE BODY','LIBRARY','PROGRAM','TYPE BODY','JAVA RESOURCE','XML SCHEMA','TRIGGER','JOB CLASS','TABLE','SYNONYM','VIEW','FUNCTION','WINDOW GROUP','INDEXTYPE','INDEX','TYPE','EVALUATION CONTEXT','JAVA CLASS')

RANGE HASH PARTITION

Bu yapıda ise partitionlarımız range subpartitionlarımız ise hash şeklinde olacaktır.

create table range_hash_part

(OWNER VARCHAR2(30 BYTE) NOT NULL,

OBJECT_NAME VARCHAR2(30 BYTE) NOT NULL,

SUBOBJECT_NAME VARCHAR2(30 BYTE),

OBJECT_ID NUMBER NOT NULL,

DATA_OBJECT_ID NUMBER,

OBJECT_TYPE VARCHAR2(19 BYTE),

CREATED DATE NOT NULL,

LAST_DDL_TIME DATE NOT NULL,

TIMESTAMP VARCHAR2(19 BYTE),

STATUS VARCHAR2(7 BYTE),

TEMPORARY VARCHAR2(1 BYTE),

GENERATED VARCHAR2(1 BYTE),

SECONDARY VARCHAR2(1 BYTE)

)

partition by range (object_id)

subpartition by hash (object_name)

--tek tek her partition için yazmaktan ise aşağıdaki gibi bir template oluşturarak

--hepsinde yaratılmasını sağlarız

subpartition template(

subpartition sp1 tablespace users,

subpartition sp2 tablespace users,

subpartition sp3 tablespace users,

subpartition sp4 tablespace example)

(partition part_001 values less than (20000),

partition part_002 values less than (40000),

partition part_003 values less than (60000),

partition part_004 values less than (maxvalue));

insert into range_hash_part select * from all_objects

--Oluşturduğumuz subpartition’ları aşağıdaki sorgu ile görebiliriz.

select * from user_tab_SUBpartitions where table_name='RANGE_HASH_PART'

RANGE LIST PARTITION

Buradaki yapıda da partition’ları range şeklinde oluşturuyorum. Subpartition’lar ise list şeklinde.

create table range_list_part

(OWNER VARCHAR2(30 BYTE) NOT NULL,

OBJECT_NAME VARCHAR2(30 BYTE) NOT NULL,

SUBOBJECT_NAME VARCHAR2(30 BYTE),

OBJECT_ID NUMBER NOT NULL,

DATA_OBJECT_ID NUMBER,

OBJECT_TYPE VARCHAR2(19 BYTE),

CREATED DATE NOT NULL,

LAST_DDL_TIME DATE NOT NULL,

TIMESTAMP VARCHAR2(19 BYTE),

STATUS VARCHAR2(7 BYTE),

TEMPORARY VARCHAR2(1 BYTE),

GENERATED VARCHAR2(1 BYTE),

SECONDARY VARCHAR2(1 BYTE)

)

partition by range (object_id)

subpartition by list (object_type)

(partition part_01 values less than (20000)

(

subpartition sub01_part_01 values ('TABLE','VIEW','INDEX'),

subpartition sub01_part_02 values ('SEQUENCE','PROCEDURE','PACKAGE')

),

partition part_02 values less than (40000)

(

subpartition sub02_part_01 values ('TABLE','VIEW','INDEX'),

subpartition sub02_part_02 values ('SEQUENCE','PROCEDURE','PACKAGE')

),

partition part_03 values less than (maxvalue)

(

subpartition sub03_part_01 values ('TABLE','VIEW','INDEX'),

subpartition sub03_part_02 values ('SEQUENCE','PROCEDURE','PACKAGE')

)

);

Bu tablo’yu doldurmak için aşağıdaki sorguyu kullanabiliriz. Gönül isterdi bütün object_type’ları almak ama yazma işi biraz ameliliğe döneceği için işin kolayına kaçtım :)).

insert into range_list_part select * from all_objects

where object_type in ('SEQUENCE','PROCEDURE','PACKAGE','TABLE','VIEW','INDEX')