Мы выполняем хранимую процедуру для извлечения BLOBS
из базы данных каждый день примерно за последние 5 лет. Обычно мы извлекаем около 25 файлов каждую ночь, причем большинство составляет примерно 500 КБ в размере, а количество пользователей около 10 000 КБ.Извлечение из базы данных BLOB получает медленнее
Этот процесс никогда не был самым быстрым, но после перемещения центров обработки данных этот процесс может занять 12 часов. Это само по себе шокирует, когда вы только извлекаете ~ 55 МБ или около того. Мы привлекли все соответствующие команды, чтобы взглянуть на производительность Oracle, диск ввода-вывода и т. Д., И они утверждают, что все идеально.
Я читал о 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;
/
EDIT
Выполнение плана по CURSOR extract_cur
.
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')
Вы пытались собрать статистику на столе 'staging'? – GurV
@GurwinderSingh, который обычно делается в базе данных каждый месяц. Это не особенно большая база данных ... 25 нечетных записей в день, и мы сохраняем только 30-дневную стоимость. – hshah
Вы можете получить план выполнения запроса курсора и вставить вопрос? – GurV