2011-10-12 5 views
2

대량 수집을 쿼리하는 방법은 무엇입니까? 예를 들어 내가 가지고있는 경우오라클에 대량 수집

namesValues는 dbms_sql.varchar2_table입니다.

지금, 나는 이름을 표 다른 'N'인 경우 'Y'에 is_valid 업데이트 할

name is_valid 
    v 
    h 

포함 된 다른 테이블 XYZ 있습니다. 표 1에는 1,000 만 개의 행이 있습니다. 대량 수집 후 실행하고 싶습니다

update xyz 
set is_valid ='Y' 
where name in namesValue. 

어떻게 이름을 쿼리합니까? 아니면 다른 옵션이 있습니다. 표 1에는 색인이 없습니다. 도와주세요.

+1

참조 ... 희망이 도움이 : http://download.oracle.com/docs/cd/E11882_01/server.112/e26088/statements_10002.htm#sthref6770를, 거기에서 연결 특히 예. –

답변

4

"표 1에는 색인이 없습니다."

글쎄 거기에 문제가 있습니다. 왜 안돼? TABLE1.NAME에 색인을 넣고 표준 SQL UPDATE를 사용하여 XYZ의 데이터를 수정하십시오.

대량 수집으로이 문제를 해결하려는 시도는 적절한 방법이 아닙니다.

5

톰 카이트 (오라클 (주) 부사장)는 말하기를 :

내 만트라, 내가 고집 할 것이 오, 대단히 감사합니다 :

당신은 하나에 그것을해야 가능한 경우 SQL 문.

단일 SQL 문에서 수행 할 수없는 경우 PL/SQL에서 수행하십시오.

PL/SQL에서 수행 할 수없는 경우 Java 저장 프로 시저를 사용해보십시오.

Java로 수행 할 수없는 경우 C 외부 프로 시저에서 수행하십시오.

가 세트로 생각

당신이 C 외부 루틴에 그것을 할 수없는 경우, 당신은 심각하게 당신이 그것을해야 할 이유에 대해 생각 로 할 수 있습니다 ... ...

모두가 배울 SQL에 대해 배울 수 있습니다 ...

가능한 경우 SQL로 업데이트를 수행해야합니다. 이 작업을 수행하기 위해 인덱스를 추가해야하는 경우 BULK COLLECT로 채워진 컬렉션을 반복하는 것이 바람직 할 수 있습니다.

그러나 이것은 일종의 지정입니다. 이렇게 지정해야하지만 어떻게 할 것입니까?

DB 서버에 메모리에 1,000 만 개의 레코드를 저장할 수있는 용량이 없다고 가정 했으므로 한 번에 1,000 만 개의 레코드를 모두 대량으로 수집해야합니다. 메모리 오버 헤드를 줄이기 위해 BULK COLLECT를 루프에 넣었습니다. 그렇지 않은 경우 대량 수집 루프를 생략 할 수 있습니다.

DECLARE 
    c_bulk_limit CONSTANT PLS_INTEGER := 500000; 
    -- 
    CURSOR names_cur 
    IS 
     SELECT name 
     FROM table1; 
    -- 
    TYPE namesValuesType IS TABLE OF table1.name%TYPE 
     INDEX BY PLS_INTEGER; 
    namesValues namesValuesType; 
BEGIN 

    -- Populate the collection 
    OPEN name_cur; 
    LOOP 
     -- Fetch the records in a loop limiting them 
     -- to the c_bulk_limit amount at a time 
     FETCH name_cur BULK COLLECT INTO namesValues 
     LIMIT c_bulk_limit; 

     -- Process the records in your collection 
     FORALL x IN INDICES OF namesValues 
     UPDATE xyz 
      SET is_valid ='Y' 
      WHERE name = namesValue(x) 
      AND is_valid != 'Y'; 

     -- Set up loop exit criteria 
     EXIT WHEN namesValues.COUNT < c_bulk_limit; 
    END LOOP; 
    CLOSE name_cur; 

    -- You want to update all remaining rows to 'N' 
    UPDATE xyz 
     SET is_valid ='N' 
    WHERE is_valid IS NULL; 

EXCEPTION 
    WHEN others 
    THEN 
     IF name_cur%ISOPEN 
     THEN 
     CLOSE name_cur; 
     END IF; 
     -- Re-raise the exception; 
     RAISE; 
END; 
/

등 롤백 세그먼트 크기에 따라 루프를 수집하는 대량 내에서 중간 커밋을 발행하지만 다음 이러한 변경 사항을 롤백 할 수 없다는 것을 인식 할 수 있습니다. 나는 의도적으로 이것에 COMMITs를 추가하지 않았으므로 시스템에 적합한 위치를 선택할 수 있습니다.

사용 가능한 리소스에 따라 c_bulk_limit 상수의 크기를 변경할 수도 있습니다.

xyz 테이블이 크고 name 열에 인덱스가없는 경우에도 업데이트로 인해 문제가 발생합니다.