분류

2019년 2월 26일 화요일

대용량 데이터 처리 2. 오라클 병렬처리 parallel

1.PARALLEL은 언제 사용합니까?

병렬처리는 한 번에 대용량의 데이터를 처리할 경우 발생되는 부하를 여러 쓰레드에 분산처리 하는 기술입니다. 따라서 일반적인 조회나, 데이터 처리에는 INDEX를 통한 범위 처리를 주로 사용하게 됩니다. 병렬처리의 사용 빈도는 낮으며, 대용량 데이터 처리를 위한 프로시저나 프로그램에서 조심스럽게 사용됩니다. 개념적인 그림은 API에 잘 나와있어 참조하시면 되겠습니다.

오라클 병렬처리 API

이전 기술한 java 다중 쓰레드와 비슷한 구조를 갖고 있습니다. 자바의 thread와 비교한다면 thread.submit() 정도의 처리를 통해 개별 쓰레드에서 처리된 결과 집합을 재처리하는 기술이 잘 만들어져있다. 정도로 생각해도 괜찮을 것 같습니다.

2. 병렬처리 환경 정보 확인 

oracle 시스템의 환경 변수는 간단한 명령을 통해 확인할 수 있습니다. 
  select * from 
    v$parameter
  where 
  name like '%parallel%'; 

ORACLE 병렬처리 환경 문서 API
1. parallel_server : true 로 설정될 경우 병렬 서버 모드로 시작됨.
2. parallel_adaptive_multi_user : 시스템 과부하를 방지하기 위해 사용자의 병렬처리 수준을 제어합니다.

 예 : SELECT /+*PARALLEL(8)*/ * FROM DUAL; 명령의 PARALLEL(차수)에 해당함
      혹은 alter table emp parallel 8;
이처럼 차수를 지정하여 사용하는 것을 '수동 DOP' 옵티마이저가(쿼리 코디네이터라고 하기도 함) 자동으로 병렬 처리를 지정하는 것을 '자동 DOP'라고 합니다.

3. parallel_degree_limit : 자동 DOP가 사용 중일 때 한계 병렬처리 차수를 설정합니다.
(기본 값은 cpu 수 x cpu당 병렬처리 쓰레드 수 x 활성 인스턴스 수)
4. parallel_degree_policy : 자동 DOP 사용 여부를 제어, 병렬처리 큐 및 메모리 내 병렬처리에 사용됩니다. 기본적으로 비활성화 되어있습니다.
5. parallel_execution_message_size : 병렬 처리 시 서버와 쓰레드, 옵티마이저간에 사용되는 버퍼사이즈. 공유 메모리풀에서 할당됨.
6. parallel_force_local : 병렬 실행을 현재 인스턴스로 제한합니다.
7. parallel_max_servers : 한 인스턴스의 병렬처리와 병렬 복구처리에 사용될 최대 병렬 차수를 지정합니다. (인스턴스 시작 시점에 발생하는 미확정 트랜잭션의 처리와 복구에 관련된 변수인 것 같습니다.) 인스턴스 시작 시 해당 수치까지 프로세스를 증가시킵니다.
이 변수를 너무 작게 설정할 경우 일부 쿼리에서 병렬처리를 수행할 수 없게 됩니다.
8. parallel_min_servers : 오라클 데이터베이스 시작을 위해 시작 시와 병렬처리 제한에 사용될 병렬처리 프로세스 수를 지정합니다. 이러한 세팅은 병렬처리의 시작 비용을 균형적으로 만들지만 병렬 처리가 종료된 이후에도 메모리와 병렬 프로세스를 반환하지 않습니다. 데이터베이스 셧다운시 반환됩니다.
9. parallel_min_percent : 병렬 실행에 허용된 최소 쓰레드 비율, 기본 값은 0이며 병렬처리 에 사용할 수 있는 프로세스가 없는 경우 직렬 처리됨.
10. parallel_servers_target : 병렬처리가 사용되기 전 서버에서 병렬 처리 대기열이 사용할 수 있는 프로세스 수.  병렬 처리 대기열은 PARALLEL_DEGREE_POLICY가 AUTO로 설정되었을 경우 사용 가능합니다.
11. parallel_threads_per_cpu : CPU당 병렬처리에 사용가능한 쓰레드 수.

3. 병렬처리 사용 시 주의사항

ORACLE API 문서와 병렬처리 환경설정은 대게 사용자가 직접 작성한 힌트를 통한 SQL을 처리를 하는 것 보다는 자동 처리에 초점이 맞춰진 것 같습니다. 하지만 실무 환경에서 이런 옵션 설정만으로 병렬 처리를 수행 할 경우 위험할 수 있습니다.

예를 들자면 동시접속자가 800명인 시스템에서 자동 병렬처리를 16개씩 자동으로 사용하게 했다고 칩시다. 물론 동시에 조회 버튼을 땅~ 하고 칠 리는 없지만 그래도 동시에 조회버튼을 눌렀다고 상정 할 경우 사용해야하는 쓰레드의 수는 12800개입니다. 당연히 시스템에 과부하가 생길 것 입니다. 그래서 OLTP환경에서는 대게 사용하지 않습니다. 또한 동시접속자가 많을 것으로 예상되는 데이터베이스의 경우 병렬모드를 사용하지 않게 설정되었을 수 있습니다. 가장 최근 확인한 것은 v$parameter 테이블을 조회했을 경우 parallel_dgree_limit 을 변수가 존재하지 않는 환경을 확인했습니다.

DBA에게 병렬처리 수준에 대한 질의를 해야 하는 것도 이런 부분입니다. 데이터베이스 관리 시스템을 도입하는 시점에서 적정 성능을 보장받기 위해 여러가지 성능에 대한 테스트를 하는데 이 때, 병행 제어 수준에 대한 테스트도 수행하기에 해당 문서를 갖고 있다면 현행 DBMS의 사용자 수와 그에 맞는 병행 제어 수준을 도출할 수 있기 때문입니다.

OLTP 환경의 조회 SQL에서 수행이 느릴 경우 대책으로 가장 많이 사용되는 것은 PARALLEL이 아닌 SQL에 대한 제약조건 강화를 하는 것이 보편적이고, DELETE 속도가 느릴 경우 역시 PARALLEL처리보다는 해당 데이터 영역을 파티션 테이블로 만들어 파티션에 대한 TRUNCATE를 수행하는 경우가 더 많습니다.
(물론 TRUNCATE 역시 복구 불가에 대한 공포증으로 사용하지 않는 사람도 많습니다.)

병렬 처리는 만능이 아니며 부주의하게 사용할 경우 문제가 발생하기에 아예 기피하는 사람도 있습니다.

개인적으로는 파라미터 설정 중 parallel_max_server 값의 2.5%정도 수준에서 시작하여 5%내에서 사용하고 있습니다. 통상적으로 동시접속자 30인 이내의 데이터 가공 및 집계처리 환경의 DBMS를 사용하고 있고, 일과시간에 작업하는 프로그램이 대부분이기 때문입니다. 하지만 일과 외 사긴에 사용될 경우에는 병렬처리 수준을 더 높이기도 합니다. 정확한 기준이 없는 경우가 많기 때문이기도 합니다.

4. parallel 명령 사용 예 

가. DML 사용 예

1) SELECT , DELETE, INSERT, UPDATE, MERGE 명령의 바로 뒤에
   SELECT /*+PARALLEL(16)*/ * FROM 테이블;
   DELETE /*+PARALLEL(16)*/  FROM 테이블;

2) JOIN 시에는 테이블 마다(그렇지 않을 경우 테이블 수 X PARALLEL 개수만큼의 병렬 처리가 생성됨.
  SELECT /*+PARALLEL(A 16)(B 16)*/  * FROM 테이블 A , 테이블 B  WHERE A.ID = B.ID;

※ DBMS 설정에 따라 병렬처리 사용을 세션단위로 허용해야 하는 경우 아래 명령을 사용
ALTER SESSION ENABLE PARALLEL DML;

3) 병렬 처리와 일반처리의 실행계획 차이
SELECT * FROM TABLE 플랜 (병렬 힌트를 줬으나 미 적용시에도 동일)
-----------------------------------------------------------------------------------------
 SELECT STATMENT ALL_ROWS
    Cost : 332,704 Bytes:8,402,920,050 Cardinality : 52,192,050
      PARTITION LIST ALL
        Cost : 332,704 Bytes:8,402,920,050 Cardinality : 52,192,050
          Partition #: Partition accessed #1 - #7 
            TABLE ACCESS FULL TABLE...
             Cost : 332,704 Bytes:8,402,920,050 Cardinality : 52,192,050
                Partition #: Partition accessed #1 - #7
--------------------------------------------------------------------------------------------------------------

SELECT /*+PARALLEL(16)*/ FROM TABLE (병렬힌트가 적용되었을경우) 
병렬처리 코디네이터가 실행계획에 등장하게 됩니다. 
--------------------------------------------------------------------------------------------------------------
SELECT STATMENT ALL_ROWS
    Cost : 332,704 Bytes:8,402,920,050 Cardinality : 52,192,050
      PX COORDINATOR
          PX SEND QC(RANDOM) PARALLEL_TO_SERIAL_SYS.:TQ1000:Q1000
            Cost : 332,704 Bytes:8,402,920,050 Cardinality : 52,192,050
                   PX BLOCK ITERATOR PARALLEL_COMBINED_WITH_CHILD.:TQ1000:Q1000
                   Cost : 332,704 Bytes:8,402,920,050 Cardinality : 52,192,050
                        Partition #: Partition accessed #1 - #7 
                      TABLE ACCESS FULL TABLE...
                         Cost : 332,704 Bytes:8,402,920,050 Cardinality : 52,192,050
                               Partition #: Partition accessed #1 - #7
--------------------------------------------------------------------------------------------------------------

나. DDL 사용 예

테이블의 정의나 인덱스 정의에 병렬처리 수준을 지정할 경우 DML문을 사용할때 병렬처리 수준을 선언하지 않아도 자동적용이 됩니다. 조인 처리가 될 경우의 병렬 수준에 대한 고려는 직접 해본적이 없기에 저도 잘 모르겠습니다. 알게되면 좀더 보완하도록 하겠습니다.
1) 테이블, 인덱스 등의 변경
ALTER TABLE 테이블명 PARALLEL 16;
ALTER INDEX 인덱스명 PARALLEL 16;

2) 테이블 인덱스 등의 생성
CREATE TABLE 테이블명 (컬럼명 컬럼타입+길이,...) PARALLEL (DEGREE 16 INSTANCES 1)
CREATE INDEX 인덱스명 ON 테이블명(컬럼명...) PARALLEL  (DEGREE 16 INSTANCES 1)

5. 기타 

실행계획의 차이에 대해서 기술해보려 했으나 PARALLEL로 생성된 테이블이나 인덱스와, 힌트를 통한 /*+PARALLEL(16)*/의 실행 계획 차이는 정말 미묘했습니다. COST가 1정도 차이가 나거나, 거의 차이가 없는 유사한 모습이 보여, 차이라고 할 수 없는 애매모호한 상황이 되었습니다.

개인적으로는 OLTP환경에서는 DML을 이용하여 PARALLEL을 사용하는 것을 금하고 있습니다. 다중 사용자의 트랜잭션에 의해 발생할 수 있는 병렬처리 락 때문입니다. 반면 동시 접속자가 적고 통계 위주의 시스템 환경이라면 PARALLEL을 적극적으로 사용하는 편입니다.

이상입니다. 수정이나 의견이 있으신 분은 댓글 달아주시면 고맙겠습니다.

연관된 문서가 있습니다.
대용량 데이터 처리 1. java 다중쓰레드 활용
대용량 데이터 처리 2. 오라클 병렬처리 parallel
대용량 데이터 처리 3. 테이블 파티셔닝
대용량 데이터 처리 4. DBMS_JOB

댓글 없음:

댓글 쓰기