Aktif kullanılan tabloya en hızlı şekilde ve tabloyu kilitlemeden arşiv logu üretmeden hafıza ve undo alanlarını doldurmadan nasıl büyük veriyi ekleyebiliriz?
Oracle 'da bunun için BULK COLLECT ve FORALL kullanarak yapabiliriz.
Arşiv log üretmemek için öncelikle INSERT yapılacak tablonun bulunduğu alanı
archive log üretmemesi için düzenliyoruz.
ALTER TABLESPACE <TABLESPACE_NAME> NOLOGGING;
Aşağıdaki prosedürü oluşturarak çalıştırabilirsiniz.
CREATE OR REPLACE PROCEDURE <SCHEMA>.<PROCEDURE_NAME>
IS
TYPE fetch1 IS TABLE OF <TABLE_NAME>%ROWTYPE;
l_array fetch1;
CURSOR cur_1 IS SELECT * FROM <TABLE_NAME>;
l_start NUMBER;
BEGIN
l_start := DBMS_UTILITY.get_time;
DBMS_OUTPUT.PUT_LINE('Time Started : ' || TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS'));
OPEN cur_1;
LOOP
FETCH cur_1 BULK COLLECT INTO l_array LIMIT 100000;
DBMS_OUTPUT.put_line('Collected : ' || (DBMS_UTILITY.get_time - l_start));
EXIT WHEN l_array.count = 0;
l_start := DBMS_UTILITY.get_time;
FORALL i IN l_array.FIRST .. l_array.LAST SAVE EXCEPTIONS
INSERT /*+ APPEND */ INTO <TABLE_NAME> VALUES l_array(i);
COMMIT;
DBMS_OUTPUT.PUT_LINE('100000 Rows Inserted : ' || (DBMS_UTILITY.get_time - l_start));
END LOOP;
DBMS_OUTPUT.PUT_LINE('Time Finished : ' || TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS'));
CLOSE cur_1;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (SQLERRM);
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line ('Rows inserted : ' || SQL%ROWCOUNT);
DBMS_OUTPUT.put_line('Number of failures: ' || SQL%BULK_EXCEPTIONS.count);
DBMS_OUTPUT.put_line (SQLERRM);
FOR indx IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
DBMS_OUTPUT.put_line ('Error '|| indx || ' occurred on index '
|| SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX
|| ' attempting to update name to "'
|| SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX || '"');
DBMS_OUTPUT.put_line (
'Oracle error is : '
|| SQLERRM(-SQL%BULK_EXCEPTIONS(indx).ERROR_CODE));
END LOOP;
ROLLBACK;
END;
Tabloların ve prosedürün aynı şemada olmasına dikkat ediniz! Çünkü "TYPE
fetch1 IS TABLE OF <TABLE_NAME>%ROWTYPE;" kısmında şema ismini
giremiyorsunuz sadece tablo ismi girebiliyorsunuz.Eğer aynı yerde olamayacak
ise aşağıdaki komutu da çalıştırmayı yada prosedürünüze eklemeyi unutmayın.
ALTER SESSION SET CURRENT_SCHEMA=<SCHEMA_NAME>;
Ben bu procedürü bir partition için 200 milyondan fazla kayıt INSERT edeceğim
için işlem günlerce sürdü.İşlemin bu günler içinde kesintiye uğramaması için
ben DBMS_SCHEDULER_JOB kullanarak sunucu tarafında arka planda
çalıştırdım.Günlerce sürecek işlem için direkt bilgisayarınızdan değilde
sunucu taraflı çalıştırmayı tercih etmelisiniz.
Diğer bir konuda APPEND_VALUES hint yerine ben APPEND kullandım.APPEND_VALUES
ile kullanırken aktif kullanılan tabloyu kilitlediğini uygulamanın çalışamaz
duruma geldiğini farkettim.Aradaki farkları araştırarak siz amacınıza uygun
olanı tercih edebilirsiniz.
Kaynaklar :
Etiketler :
Oracle