우리는 지난 5 년간 매일 데이터베이스에서 BLOBS
을 추출하는 저장 프로 시저를 실행 해 왔습니다. 일반적으로 우리는 매일 약 25 개의 파일을 추출합니다. 대다수의 파일 크기는 약 500KB이고 소수는 10,000KB입니다.데이터베이스에서 추출 BLOB가 느림
프로세스가 가장 빠른 적이 없었지만 데이터 센터를 이동 한 후이 프로세스를 12 시간 이상 수행 할 수 있습니다. 55MB 정도만 압축하면 그 자체로 충격적입니다. 우리는 Oracle, 디스크 I/O 등의 성능을 살펴보기 위해 모든 관련 팀을 참여 시켰으며 모든 것이 완벽하다고 주장합니다. 내가 읽어 봤는데
약 UTL_FILE
및 DBMS_LOB.read
, 본 사람들은 내가이 어떤 의미를 알아낼 수 없습니다 솔직히 말해서 등 각 루프 후 pos
를 재설정에 대해 이야기하고, 일반적인 합의는 것이있다 동일한 결과를 달성하는 훨씬 더 좋은 방법입니다.
우리는 불행히도 리팩토링에 대한 자유가 없으므로 누구나 우리 절차에서 눈부신 부분을 볼 수 있습니까? 나는 단지 내가 완전히 이해하지 못하는 것을 고심하고 있으며 우리 인프라를 유지하는 사람들은이 코드에 그것을 모두 탓하고 손을 씻는다.
CREATE OR REPLACE PROCEDURE PKG_EXTRACT (l_brand IN VARCHAR2) AS
l_file UTL_FILE.FILE_TYPE;
l_buffer RAW(32767);
l_amount BINARY_INTEGER := 32767;
l_pos INTEGER;
l_blob BLOB;
l_blob_len INTEGER;
x NUMBER;
l_file_name VARCHAR2(200);
l_count INTEGER := 1;
v_code NUMBER;
v_errm VARCHAR2(64);
log_file UTL_FILE.FILE_TYPE;
rec_num number;
BEGIN
DECLARE
CURSOR extract_cur IS
SELECT DATA, BIN_NAME
FROM STAGING
WHERE UPPER(EXTRACTED)='N';
BEGIN
log_file := UTL_FILE.fopen('DATA_DOWNLOAD_DIR','pkg_extract.log','a', 32767);
UTL_FILE.put_line(log_file,'Logging is being done in 24 hours format - V1.5 ',TRUE);
UTL_FILE.put_line(log_file,'Extract procedure started on Date-Time = '|| TO_TIMESTAMP(LOCALTIMESTAMP, 'DD-MON-RR,HH24.MI.SSXFF'),TRUE);
select count(1) into rec_num from staging;
UTL_FILE.put_line(log_file,'Total Number of records found = ' || rec_num , TRUE);
select count(1) into rec_num from staging where UPPER(EXTRACTED)='N';
UTL_FILE.put_line(log_file,'Total Number of records matching criteria = ' || rec_num , TRUE);
dbms_output.put_line('Loop through records and write them to file');
FOR extract_rec IN extract_cur
LOOP
l_pos := 1;
l_blob := extract_rec.DATA;
l_blob_len := DBMS_LOB.getlength(l_blob);
-- Save blob length.
x := l_blob_len;
l_file_name := extract_rec.BIN_NAME ;
-- Open the destination file.
dbms_output.put_line('Open the destination file:- ' || l_file_name);
l_file := UTL_FILE.fopen('DATA_DOWNLOAD_DIR',l_file_name,'wb', 32767);
dbms_output.put_line('File opened');
-- Read chunks of the BLOB and write them to the file until complete.
dbms_output.put_line('l_pos:- ' || l_pos);
dbms_output.put_line('l_blob_len:- ' || l_blob_len);
WHILE l_pos <= l_blob_len
LOOP
dbms_output.put_line('DBMS_LOB.read from position: ' || l_pos);
DBMS_LOB.read(l_blob, l_amount, l_pos, l_buffer);
dbms_output.put_line('UTL_FILE.put_raw');
UTL_FILE.put_raw(l_file, l_buffer, TRUE);
dbms_output.put_line('Written ' || l_amount || ' bytes of data starting at position: ' || l_pos);
-- Set the start position for the next cut.
l_pos := l_pos + l_amount;
--updating the extract field
dbms_output.put_line(extract_rec.BIN_NAME);
END LOOP;
l_count := l_count + 1;
-- Close the file.
dbms_output.put_line('Close the file:- ' || l_file_name);
UTL_FILE.fclose(l_file);
update staging set extracted='Y', extract_timestamp=sysdate where bin_name=extract_rec.BIN_NAME;
commit;
END LOOP;
UTL_FILE.put_line(log_file,'Extract procedure Completed on Date-Time = '|| TO_TIMESTAMP(LOCALTIMESTAMP, 'DD-MON-RR,HH24.MI.SSXFF'),TRUE);
IF UTL_FILE.is_open(log_file) THEN
UTL_FILE.fclose(log_file);
end if;
END;
EXCEPTION
WHEN OTHERS THEN
v_code := SQLCODE;
v_errm := SUBSTR(SQLERRM, 1, 64);
dbms_output.put_line('Error code ' || v_code || ': ' || v_errm);
UTL_FILE.put_line(log_file,'--------------------------------------' ,TRUE);
UTL_FILE.put_line(log_file,'Error Occurred while executing '||'Error code ' || v_code || ': ' || v_errm ,TRUE);
UTL_FILE.put_line(log_file,'Extract procedure Completed with errors - '|| TO_TIMESTAMP(LOCALTIMESTAMP, 'DD-MON-RR,HH24.MI.SSXFF'),TRUE);
UTL_FILE.put_line(log_file,'--------------------------------------' ,TRUE);
-- Close the file if something goes wrong.
IF UTL_FILE.is_open(l_file) THEN
UTL_FILE.fclose(l_file);
IF UTL_FILE.is_open(log_file) THEN
UTL_FILE.fclose(log_file);
end if;
END IF;
RAISE;
END;
/
을 편집 CURSOR extract_cur
에 대한
실행 계획. 내가 코드를 변경, 그래서 이런 일을 피하려고 select count(1) into rec_num from staging
/SQL 그렇게보다 효율적으로 사용하는 커서를 PL 무엇 오라클 있기 때문에 PL/변환 여기 않는 SQL 및 SQL에 SQL
Plan hash value: 3428151562
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6 | 678 | 9 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| STAGING | 6 | 678 | 9 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(UPPER("S"."EXTRACTED")='N')
'준비'테이블에서 통계를 수집 해 보았습니까? – GurV
@ GurwinderSingh 일반적으로 매달 데이터베이스에서 수행됩니다. 그것은 특히 큰 데이터베이스가 아닙니다 ... 하루 25 건의 레코드와 30 일간의 가치 만 지니고 있습니다. – hshah
커서의 쿼리에 대한 실행 계획을 가져 와서 질문에 붙여 넣을 수 있습니까? – GurV