2012-05-04 3 views
2

기존 Oracle blob을 파일로 마이그레이션해야하는 프로젝트를 진행 중입니다. 읽기 환경은 공유 된 Oracle 10gR2 서버입니다. 현재 UTL_FILE을 사용하는 스크립트가 있습니다. 그러나 프로세스가 꽤 느립니다. 25GB의 샘플 데이터를 추출하는 데 약 3 시간이 걸립니다. 이동할 실제 데이터는 1TB 단위입니다. 이 튜닝에 큰 도움이 필요합니다. 여기 Oracle BLOBS를 파일로 대량 추출 - 조언/튜닝 도움 필요

내 프로세스입니다 블롭 ID의 목록과 이름
  • 시작 BLOB2FILE를 사용하여 덩어리를 추출 각 방울
  • 를 통해 갈 수있는 루프를 가져

    1. 열기 커서, a는 사용자 지정 저장 절차 (웹 사이트에서 그것을 집어 약간 수정) 여기

  • 코드입니다 :

    create or replace 
    PROCEDURE BLOB2File(
        lngBlobID IN NUMBER, 
        sFileName IN VARCHAR2, 
        sDir  IN VARCHAR2) 
    AS 
        iFileLen INTEGER; 
        iLineLen INTEGER := 32000; -- max line size for utl_file 
        vStart NUMBER := 1; 
        vBlob BLOB; 
        l_output utl_file.file_type; 
        my_vr RAW(32000); 
        iTmp INTEGER; 
    BEGIN 
        -- get blob details 
        LOG_IT('Entered. Blob Id: ' || lngBlobID || ', File Name: ' || sFileName || ', Directory: ' || sDir); 
        SELECT blobData, 
        lengthb(blobData) 
        INTO vBlob, 
        iFileLen 
        FROM blobTable 
        WHERE id = lngBlobID; 
        LOG_IT('Acquired the blob. Blob size: ' || TO_CHAR(iFileLen)); 
        l_output := utl_file.fopen(sDir, sFileName,'wb', iLineLen); 
        vStart := 1; 
        iTmp  := iFileLen; 
        -- if small enough for a single write 
        IF iFileLen < iLineLen THEN 
        utl_file.put_raw(l_output,vBlob); 
        utl_file.fflush(l_output); 
        ELSE -- write in pieces 
        vStart  := 1; 
        WHILE vStart < iFileLen AND iLineLen > 0 
        LOOP 
         dbms_lob.read(vBlob,iLineLen,vStart,my_vr); 
         utl_file.put_raw(l_output,my_vr); 
         utl_file.fflush(l_output); 
         -- set the start position for the next cut 
         vStart := vStart + iLineLen; 
         -- set the end position if less than 32000 bytes 
         iTmp  := iTmp - iLineLen; 
         IF iTmp  < iLineLen THEN 
         iLineLen := iTmp; 
         END IF; 
        END LOOP; 
        END IF; 
        utl_file.fclose(l_output); 
        LOG_IT('Exited'); 
    
        EXCEPTION 
        WHEN OTHERS THEN 
        LOG_IT('**ERROR** ' || SQLERRM, SQLCODE, DBMS_UTILITY.FORMAT_ERROR_BACKTRACE); 
    END; 
    

    LOG_IT는 테이블에 로깅되는 저장된 proc입니다. 거기에 어떤 중요한 히트가 있어서는 안됩니다. 일반적인 FETCH 대신 BULK FETCH를 사용하여 1 단계 최적화를 시도했습니다. 그러나, 어떤 중요한 결과도 나오지 않았습니다.

    누구나 개선을위한 아이디어를 제시 할 수 있습니까? 아니면 더 나은 방법으로이 문제에 접근 할 수 있습니까?

    답변

    2

    하드웨어가 sDir에 8GB/시간 이상의 지속적인 쓰기를 처리하고 (blobTable에서 비슷한 양의 판독을 처리하고 시스템에 필요한 다른 I/O를 처리하는 데 충분하다고 가정 할 때) 가장 간단한 옵션 이 프로 시저를 호출하는 몇 개의 병렬 세션을 생성하는 것입니다. 예를 들어 하나의 LOB을 추출하는 각각 세 개의 작업을 병렬로 실행하려면 다음과 같이 할 수 있습니다.

    DECLARE 
        l_jobno INTEGER; 
    BEGIN 
        dbms_job.submit(l_jobno, 'begin BLOB2File(1, ''1.lob'', ''DIRECTORY''); end;', sysdate + interval '5' second); 
        dbms_job.submit(l_jobno, 'begin BLOB2File(2, ''2.lob'', ''DIRECTORY''); end;', sysdate + interval '5' second); 
        dbms_job.submit(l_jobno, 'begin BLOB2File(3, ''3.lob'', ''DIRECTORY''); end;', sysdate + interval '5' second); 
        commit; 
    END; 
    

    당신은 아마 당신이 아마 작업의 작은 숫자를 생성하고 작업 할 그들에게 lngBlobID 각 값의 범위를 제공 할 reality--의 모든 BLOB에 대한 별도의 스레드를 갖고 싶어하지 않습니다. 오라클이 한 번에 실행할 작업의 수는 JOB_QUEUE_PROCESSES 매개 변수로 제한되므로 수천 개의 작업을 제출할 수 있으며 Oracle에서 동시에 실행할 수있는 작업 수를 제한 할 수 있습니다.

    +0

    감사합니다. 가능하고 도움이 될 것 같습니다. 확실히 이것을 시도 할 것입니다. 그러나 db가 공유 환경에 있기 때문에 많은 작업을 제출해도 서버가 다운되거나 다른 사용자의 작업 속도가 느려지기를 바랍니다. – sammy

    +0

    @sammy - 물론, 동시에 실행하는 작업이 많을수록 더 많은 I/O 리소스를 사용할 수 있고 다른 I/O 리소스도 적게 사용할 수 있습니다. 그렇기 때문에 시스템의 다른 사용자의 요구를 고려한 후 악용 할 수있는 하드웨어의 I/O 대역폭이 얼마나되는지에 대해 이야기하기 시작했습니다. –

    +0

    제출할 수있는 작업 수에 제한이 있습니까? 나는 약 50 만 개의 파일을 가져야합니다. – sammy