Zaman zaman database’ de
tablolara yüklü miktarda insert işlemleri olur. Özellikle bahsettiğimiz bir
raporlama database’ ise bu işlem kaçınılmaz olur ve yapılan işlemin boyutu
undo tablespace’ inizin boyutundan fazla olduğunda (undo tbs autoextend
olmadığını varsayarsak) “ORA-30036: unable to extend
segment by 8 in undo tablespace 'UNDOTBS2'” hatasını almanız kaçınılmaz olacaktır. Ora-30036 hatasının önüne
geçmek için yapılan insert işlemini parçalamak ve daha ufak bölümlerde yapmak
sizin için kaçınılmaz bir çözüm olacaktır. Bu işlemi de yaparken tablo
içerisindeki bir alana göre bir den fazla where conditionı ile sorgu yazmak
yerine tek sorgu ile ama belirli sayıda data üzerinde sırayla işlem yaparak
undo’ ya fazla yüklenmeden tabiri caizse patlatmadan işleminizi
gerçekleştirebilirsiniz. Örnek olması açısından şöyle bir bilgi verebilirim,
raporlama database’ lerimizden birinde yer alan 54 gb bir datayı farklı bir schema
altına aşağıdaki script ile yaklaşık 1 saat gibi bir sürede taşımıştım.
(Aşağıda belirtmiş olduğum tuning yöntemlerinden hiçbirini kullanmadan) Tabi bu
süreyi etkileyen diğer faktörleride göz önünde bulundurmak lazım. (işlemin
yapıldığı andaki database deki yoğunluk, kullanılan server’ ın kapasitesi,
taşınan tablespace’ lere ait dbf’ ler üzerindeki o anki i/o durumu vs.)
Aşağıdaki scripti çalıştırmadan önce hangi tabloyu taşıtacak iseniz o
tablonun DDL’ ini taşıyacağınız ortamda öncelikle çalıştırıp tabloyu boş olarak
oluşturuyorsunuz. Sonrasında scriptin
içerisindeki select ve insert kısımlarını bir sefere mahsus düzenlemeniz
yeterli olacaktır.
DECLARE
v_time NUMBER;
BEGIN
DBMS_OUTPUT.put_line
('Started');
v_time :=
DBMS_UTILITY.get_time;
FOR r IN (SELECT ROWNUM,
mesaj_no, islem_kodu, atm_kodu, kart_no,
son_kul_tar, mesaj_date, mesaj_time, stan, responce,
responce_detay, mesaj, tarih, saat
FROM atm_mesaj_log)
LOOP
INSERT INTO atm_mesaj_log_hist
(mesaj_no, islem_kodu, atm_kodu, kart_no,
son_kul_tar, mesaj_date, mesaj_time, stan,
responce, responce_detay, mesaj, tarih, saat
)
VALUES (r.mesaj_no, r.islem_kodu, r.atm_kodu, r.kart_no,
r.son_kul_tar, r.mesaj_date, r.mesaj_time, r.stan,
r.responce, r.responce_detay, r.mesaj, r.tarih, r.saat
);
IF (MOD (r.ROWNUM,
50000) = 0)
THEN
BEGIN
COMMIT;
DBMS_OUTPUT.put_line ('commit executed');
END;
END IF;
END LOOP;
DBMS_OUTPUT.put_line
( 'time used: '
|| (DBMS_UTILITY.get_time - v_time) / 100
|| ' secs'
);
DBMS_OUTPUT.put_line
('Finished');
COMMIT;
END;
/
Scripte yer alan “IF (MOD (r.ROWNUM, 50000) = 0)” bu kısım kaç satırda bir commit işlemini gerçektireceğini belirttiğiniz
kısımdır. Bu sayede milyonlarca kaydı bir seferde insert etmek yerine parça
parça hata almadan (ki unutmayın database üzerinde çalışan tek kişi siz
değilsiniz J) işleminizi
tamamlayabilirsiniz.
Son ve önemli bir not, yukarıdaki script ile işleminize hız katmak
istiyorsanız, aşağıdaki ufak tuning bilgileri işleminizi son derece kısaltacaktır.
- tablo üzerinde varsa indexleri aktarım öncesinde yaratmayın, insert
işleminiz bittiksen sonra create edebilirsiniz.
- İnsert scriptine /*+ Append */ hintini mutlaka verin.
- Database’ iniz archive modda ama force logging modda değilse tablonun logging type’ ını işlem öncesinde NOLOGGING’ e alırsanız, işlem
sırasında redoya hiçbir kayıt atmayacağından çok daha hızlı çalışacaktır.
(işlem bittikden sonra tekrar logging moda alabilirsiniz.
Yukarıdaki scripti ve belirttiğim tuning
metotlarını kullanarak benzer bir işlem yapan olursa deneyimlerini paylaşırsa
bunuda burdan tüm arkadaşlara duyurmuş oluruz. En azından gerçekçi bir takım veriler üzerinden konuşuyor oluruz.
Hiç yorum yok:
Yorum Gönder