Oracle 19c 파티션 프루닝 안 될 때: PSTART·PSTOP과 날짜 조건 확인

Oracle 19c에서 날짜 파티션 테이블이 느리다면, 실행계획의 PSTART·PSTOP과 날짜 조건의 Predicate를 함께 확인하세요. KEY는 프루닝 실패 표시가 아니고, TABLE ACCESS FULL만으로 모든 파티션을 읽었다고 판단할 수도 없어요.

먼저 실제 파티션 키를 확인한 뒤, 컬럼에 함수를 씌운 조건과 날짜 범위 조건을 같은 데이터로 비교해 보세요. 이 글은 DATE 컬럼의 단일 RANGE 파티션을 대상으로 하며, 운영 테이블의 파티션 구조를 바꾸는 절차는 다루지 않습니다.

핵심 답변

느린 SQL의 실제 커서에서 파티션 접근 범위와 조건식을 먼저 읽으세요. KEY가 보이면 실행 시 결정되는 범위일 수 있으므로 숫자 표시로 바꾸려고 바인드를 제거하지 마세요. 날짜 조건을 고칠 때는 시작일 이상·다음 경계 미만으로 비교하되, 먼저 기존 업무 결과가 보존되는지 확인합니다.

진단 범위를 먼저 좁혀요

적용 조건·영향 범위

항목 적용/확인 내용 운영 영향 또는 예외
대상 Oracle Database 19c, DATE 키의 단일 RANGE 파티션 복합·해시·인터벌·가상 컬럼 파티션은 같은 숫자 규칙으로 해석하지 않아요.
입력 문제 SQL ID, 자식 커서, 날짜 값과 바인드 타입 같은 SQL이라도 인스턴스·컨테이너가 다르면 확인 대상이 달라져요.
권한 대상 테이블 조회와 실행계획 조회 권한 권한 오류를 프루닝 실패로 해석하지 않아요.
실습 별도 테스트 스키마와 파티션 사용 가능 환경 CREATE TABLE 권한·용량 할당·라이선스 조건을 먼저 확인해요.

프루닝은 조건에 맞지 않는 파티션을 읽기 대상에서 제외하는 과정이에요. 파티션 안에서 어떤 방식으로 행을 찾는지는 별도 판단입니다. 책에서 필요한 장을 고른 뒤 그 장의 모든 줄을 읽을 수도 있는 것처럼, 한 파티션의 전체 스캔과 테이블 전체 파티션 스캔은 구별해야 해요. Oracle 19c 파티션 프루닝과 함수·형변환의 실행계획 예제에서도 이 두 단계를 함께 볼 수 있어요.

Oracle 19c 라이선스 표에서 Partitioning은 SE2에 제공되지 않고 EE·EE-ES에서는 별도 유료 옵션으로 표시됩니다. 클라우드 상품에는 포함 여부가 다르므로 테스트 환경도 실제 계약과 서비스 구성을 확인하세요. 기능이 실행된다는 사실만으로 사용 권한을 판단하지 않습니다. Oracle 19c Oracle Partitioning 제공 범위.

PSTART와 PSTOP은 행 수가 아니에요

단순 RANGE 파티션에서 숫자로 표시된 PSTART·PSTOP은 접근할 시작·끝 파티션의 위치를 뜻해요. 행 번호나 날짜가 아닙니다. 반면 KEY와 그 부가 표시는 바인드·서브쿼리 등으로 접근 범위가 실행 시 결정되는 경우에도 나타나요. 숫자가 없다는 이유로 곧바로 전체 스캔이라고 결론 내리지 마세요. Oracle 19c 파티션 프루닝과 함수·형변환.

계획에서 읽을 신호와 다음 확인

표시 해석할 범위 다음 확인
숫자 2 → 2 단순 RANGE 예제라면 두 번째 파티션을 가리켜요. 파티션 목록의 위치와 실제 이름을 대조해요.
KEY 실행 시 범위를 정하는 경우를 포함해요. 바인드 타입·값, Predicate와 실제 실행 통계를 함께 봐요.
RANGE ALL 해당 RANGE 단계에서 전체 범위를 고려하는 계획이에요. 조건이 실제 파티션 키에 걸렸는지 확인해요.
FULL 그 아래 테이블 접근이 전체 스캔 방식이라는 뜻이에요. 상위 파티션 단계가 제한되었는지 먼저 봐요.

여러 단계가 있는 운영 계획에서는 같은 이름의 테이블이 두 번 나오거나, 테이블과 인덱스가 서로 다른 파티션 구조를 가질 수도 있어요. 계획 전체에서 숫자 하나만 찾지 말고 해당 객체의 접근 줄과 바로 위 연산자를 묶어 읽는 편이 좋아요. 아래 예제는 이 혼동을 줄이려고 인덱스와 조인을 넣지 않았습니다.

작은 월별 데이터로 조건 두 개를 비교해요

아래 코드는 문서에 맞춰 구성한 재현 예제입니다. 이 글을 작성하며 Oracle 인스턴스에서 직접 실행하지는 않았어요. 조회 합계는 샘플 데이터로 계산한 예상 결과이며, 계획의 연산자·비용·통계는 독자의 환경에서 확인해야 합니다.

운영 환경 주의

이름이 같은 기존 테이블이 없는 테스트 스키마에서만 생성하세요. 먼저 접속 대상과 스키마를 확인하고 업무 트랜잭션이 없는 별도 세션을 사용합니다. CREATE TABLE은 DDL이므로 ROLLBACK으로 생성 전 상태를 되돌리는 실습이 아니에요. Oracle 19c DDL과 암시적 커밋에서 DDL 전후의 암시적 커밋 경계를 확인할 수 있어요.

CREATE TABLE kl_prune_demo (
  order_id NUMBER NOT NULL,
  ordered_at DATE NOT NULL,
  amount NUMBER(10,2) NOT NULL
)
PARTITION BY RANGE (ordered_at) (
  PARTITION p_before VALUES LESS THAN (DATE '2026-09-01'),
  PARTITION p_sep VALUES LESS THAN (DATE '2026-10-01'),
  PARTITION p_future VALUES LESS THAN (MAXVALUE)
);

INSERT ALL
  INTO kl_prune_demo (order_id, ordered_at, amount)
    VALUES (1, DATE '2026-08-31', 10)
  INTO kl_prune_demo (order_id, ordered_at, amount)
    VALUES (2, DATE '2026-09-01', 20)
  INTO kl_prune_demo (order_id, ordered_at, amount)
    VALUES (3, DATE '2026-09-17', 40)
  INTO kl_prune_demo (order_id, ordered_at, amount)
    VALUES (4, DATE '2026-09-30' + 23/24, 50)
  INTO kl_prune_demo (order_id, ordered_at, amount)
    VALUES (5, DATE '2026-10-01', 80)
SELECT 1 FROM dual;
COMMIT;

실행 목적

목적: 경계 전·경계 당일·월말 시각을 포함한 5행을 준비해요. 권한·버전: Oracle 19c의 자기 스키마 CREATE TABLE 권한과 테이블스페이스 할당이 필요해요. 예상 결과: 세 파티션에 각각 1·3·1행이 들어가며, 명시적 COMMIT으로 샘플 입력을 확정합니다.

VALUES LESS THAN은 상한값 자체를 포함하지 않아요. 그래서 10월 1일 0시는 p_sep가 아니라 p_future에 들어갑니다. p_before는 이름과 달리 8월만이 아니라 9월 이전 전체를 담아요. 예제의 이름을 실제 날짜 제한으로 오해하지 마세요. Oracle 19c CREATE TABLE의 범위 파티션.

SELECT partition_name, partition_position, high_value
FROM user_tab_partitions
WHERE table_name = 'KL_PRUNE_DEMO'
ORDER BY partition_position;

SELECT column_name, column_position
FROM user_part_key_columns
WHERE name = 'KL_PRUNE_DEMO'
  AND object_type = 'TABLE'
ORDER BY column_position;

실행 목적

목적: 파티션 위치와 키를 확인해요. 권한·버전: Oracle 19c의 객체 소유자 계정에서 USER 뷰를 조회합니다. 예상 결과: 위치 1·2·3과 키 ORDERED_AT을 확인해요. HIGH_VALUE는 LONG 타입이므로 클라이언트의 긴 값 표시 설정에 따라 잘릴 수 있어요.

USER 뷰는 자기 소유 객체용입니다. 운영에서 다른 스키마를 볼 때는 접근 가능한 ALL 뷰와 소유자 조건으로 범위를 제한해야 해요. 파티션 위치와 경계는 Oracle 19c 파티션 순서와 경계값, 키의 순서는 Oracle 19c 파티션 키 컬럼에 정의되어 있습니다. 화면의 날짜 컬럼 이름이 익숙하더라도 실제 분할 키와 일치하는지 확인하세요.

EXPLAIN PLAN FOR
SELECT SUM(amount) AS total_amount
FROM kl_prune_demo
WHERE TO_CHAR(ordered_at, 'YYYY-MM') = '2026-09';

SELECT plan_table_output
FROM TABLE(DBMS_XPLAN.DISPLAY(
  NULL, NULL, 'TYPICAL +PARTITION +PREDICATE'
));

실행 목적

목적: 컬럼을 문자열 월로 바꾸는 조건의 예상 계획을 확인해요. 권한·버전: Oracle 19c에서 대상 조회, PLAN_TABLE 사용 및 DBMS_XPLAN 실행 권한이 필요합니다. 예상 결과: 파티션 전체 접근 여부와 TO_CHAR 조건을 찾아요. EXPLAIN PLAN은 이 SUM 조회의 실제 실행 결과를 만들지 않습니다.

파티션 키를 TO_CHAR로 감싸면 본래 날짜 범위와 직접 비교하기 어려워져 프루닝을 방해할 수 있어요. 이 예제에서는 RANGE ALL 여부를 확인합니다. 실제 계획이 다르면 결과를 억지로 맞추려고 힌트를 추가하지 말고 Predicate와 테이블 정의부터 다시 대조하세요. 함수 기반 가상 컬럼 등 다른 설계까지 이 예제의 결론을 확장하지는 않습니다. Oracle 19c 파티션 프루닝과 함수·형변환.

EXPLAIN PLAN FOR
SELECT SUM(amount) AS total_amount
FROM kl_prune_demo
WHERE ordered_at >= DATE '2026-09-01'
  AND ordered_at <  DATE '2026-10-01';

SELECT plan_table_output
FROM TABLE(DBMS_XPLAN.DISPLAY(
  NULL, NULL, 'TYPICAL +PARTITION +PREDICATE'
));

SELECT order_id, ordered_at, amount
FROM kl_prune_demo
WHERE ordered_at >= DATE '2026-09-01'
  AND ordered_at <  DATE '2026-10-01'
ORDER BY order_id;

실행 목적

목적: 같은 월을 날짜 범위로 표현하고 반환 행을 대조해요. 권한·버전: 앞선 계획 조회와 같은 Oracle 19c 테스트 계정입니다. 예상 결과: 반환 ID는 2·3·4이며 합계는 110이에요. 이 단순 구조에서는 두 번째 파티션으로 범위가 좁혀지는지 확인합니다.

DATE 리터럴은 YYYY-MM-DD 형식의 날짜를 쓰며 시각은 자정이에요. 마지막 날을 상한으로 포함하는 방식보다 다음 달 첫날 미만으로 잡으면 9월 30일 23시 샘플도 포함되고 10월 1일은 제외됩니다. Oracle 19c 날짜 리터럴. 월말 하루의 누락을 막는 문제와 프루닝 문제를 동시에 확인할 수 있는 지점이에요.

다만 기존 문자열 월 조건과 범위 조건의 의미가 항상 같다고 가정하지는 마세요. 업무의 달력 정의, 입력 날짜, NULL 처리와 시간대 변환을 확인해야 해요. 특히 TIMESTAMP WITH TIME ZONE 컬럼에는 이 DATE 예제를 그대로 붙여 넣지 않습니다. 반환 건수만 같아도 다른 행이 섞일 수 있으므로 실제 키 집합과 금액 등 업무 결과를 비교하세요.

운영에서는 실제 커서와 바인드를 확인해요

EXPLAIN PLAN은 그 시점의 예상 계획이에요. 실제 실행 환경이나 바인드 조건이 다르면 실행 커서의 계획과 달라질 수 있습니다. 운영 SQL을 날짜 리터럴로 바꿔 얻은 좋은 계획만으로 수정 완료라고 보기는 어려워요. Oracle 19c 실행계획의 예상과 실제 차이.

문제 요청에 사용된 SQL ID·자식 번호·바인드 값과 타입을 먼저 확보하세요. 아래 바인드 두 개에는 그 값을 넣습니다. SQL*Plus 계열 클라이언트라면 변수 선언 후 해당 값을 지정하고, 다른 도구라면 그 도구의 바인드 입력 기능을 쓰세요. 임의 SQL ID나 자식 번호 0을 고정해 확인하지 않습니다.

VARIABLE target_sql_id VARCHAR2(13)
VARIABLE target_child NUMBER
-- 도구에서 확인한 SQL ID와 자식 번호를 위 변수에 지정한 뒤 실행
SELECT plan_table_output
FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(
  :target_sql_id,
  :target_child,
  'ALLSTATS LAST +PARTITION +PREDICATE'
));

실행 목적

목적: 이미 실행된 지정 커서의 계획과 수집된 통계를 읽어요. 권한·버전: Oracle 19c에서 DBMS_XPLAN 실행과 V$SQL, V$SQL_PLAN, V$SESSION, V$SQL_PLAN_STATISTICS_ALL에 대한 SELECT 또는 READ 권한이 필요합니다. 예상 결과: Pstart·Pstop·Predicate를 확인하며, 실행 통계를 수집하지 않았다면 A-Rows 등은 없을 수 있어요.

DISPLAY_CURSOR의 PARTITION·PREDICATE 표시 옵션과 조회 권한은 Oracle 19c DBMS_XPLAN 출력과 권한을 기준으로 했어요. 이 호출은 대상 업무 SQL 자체를 다시 실행하는 명령은 아닙니다. 권한이나 커서 보존 문제로 조회가 안 되면 담당 DBA에게 필요한 범위의 확인을 요청하세요.

통계가 없다고 전역 STATISTICS_LEVEL을 바꾸거나 운영 SQL을 여러 번 실행하지 마세요. 테스트 환경에서 대상 문장에만 GATHER_PLAN_STATISTICS 힌트를 붙여 통계를 모으는 방법은 E-Rows와 A-Rows를 비교하는 실제 커서 진단 절차에서 이어서 볼 수 있어요. 최종 선택은 운영과 같은 바인드 타입과 대표 기간으로 재확인합니다.

바인드 방식 자체를 없애는 것은 해결책이 아니에요. 파티션 키가 DATE인데 입력을 문자열이나 다른 날짜 타입으로 전달하는지, Predicate에서 컬럼 쪽 변환이 생겼는지부터 봅니다. 드라이버 입력과 컬럼 타입을 대조하는 흐름은 바인드 타입 불일치와 컬럼 변환을 찾는 방법과 연결됩니다.

수정 전후에는 읽는 범위와 업무 결과를 같이 봐요

같은 기간·같은 데이터에서 기존 쿼리와 수정 쿼리를 비교하고, 월 시작·월말 시각·다음 달 시작처럼 경계에 걸친 입력을 꼭 포함하세요. 비교 중 데이터가 바뀌면 결과 차이가 조건 수정 때문인지 구분하기 어려우므로 테스트 복제본이나 일관된 비교 기준이 필요해요.

실행 전후 검증표

확인 수정 전 기록 수정 후 통과 기준
결과 반환 키와 금액·집계값 업무가 요구한 같은 집합·같은 집계인지 확인해요.
계획 SQL ID·자식 번호·조건식·파티션 범위 수정한 문장의 실제 커서를 다시 찾아 대조해요.
부하 대표 입력의 시간·버퍼 읽기·반환 규모 한 번의 빠른 결과가 아니라 허용한 범위에서 비교해요.
복구 기존 SQL·바인드 계약·배포 버전 결과 차이나 비용 회귀 때 이전 버전으로 돌아갈 수 있어야 해요.

Starts는 실행계획 연산자가 시작된 횟수이고 A-Rows는 그 연산자가 반환한 행 수예요. Oracle 19c 행 원본 실행 통계 정의에서 각 지표의 범위를 확인할 수 있어요. 둘을 고유 파티션 개수와 같은 숫자로 취급하면 조인 반복이나 병렬 실행에서 판단이 어긋날 수 있어요. KEY 표시와 Starts 하나만으로 “정확히 두 파티션을 읽었다”는 식의 결론을 만들지 마세요. Oracle 19c 실행계획의 예상과 실제 차이.

파티션이 줄어도 선택된 한 달의 데이터가 대부분이라면 많이 읽는 것이 정상일 수 있어요. 좁혀진 범위에서 여전히 느리면 반환 규모, 조인 뒤 행 증가, 정렬 같은 다음 병목을 따로 살펴봅니다. 서로 다른 기간을 비교해 숫자만 줄었다고 개선으로 기록하지는 마세요.

조회 수정의 영향과 되돌릴 경계를 정해요

운영 환경 주의

실제 SELECT를 반복하면 데이터를 바꾸지 않아도 CPU·I/O와 동시 업무에 부담을 줄 수 있어요. 실행 시간·읽기량의 중단 기준을 정하고 작은 테스트부터 진행하세요. 진단을 이유로 운영 파티션을 DROP·TRUNCATE하거나 분할 구조를 바꾸지 않습니다.

날짜 조건을 수정하는 이번 절차에는 운영 DDL이 필요하지 않아요. SQL 배포를 되돌릴 때는 이전 조건식과 바인드 타입을 함께 복구하고, 응답 결과와 실행 비용이 돌아왔는지 확인합니다. 이미 외부로 전달된 잘못된 보고서나 후속 업무까지 데이터베이스 ROLLBACK으로 되돌릴 수 있는 것은 아니에요.

롤백 방법

샘플 INSERT를 COMMIT하기 전이라면 ROLLBACK으로 입력을 취소할 수 있지만, 위 예제처럼 COMMIT한 뒤에는 해당하지 않아요. 실습 정리는 자기 테스트 테이블임을 확인한 후에만 수행합니다. 운영 배포는 보관한 이전 SQL·바인딩 구현으로 되돌리고 업무 결과를 재확인하세요.

DROP TABLE kl_prune_demo;

실행 목적

목적: 이번 실습에서 만든 테이블만 정리해요. 권한·버전: Oracle 19c의 해당 객체 소유자 계정입니다. 예상 결과: 테스트 객체를 더 이상 일반 조회할 수 없어요. DROP은 DDL이므로 ROLLBACK 복구 대상으로 보지 않으며, 필요 데이터가 남아 있다면 실행하지 마세요.

숫자를 바꾸기보다 원인을 남겨요

점검 기록에는 “FULL을 없앴다”보다 어떤 날짜 조건에서 어느 파티션 범위를 고려했고, 결과와 읽기 비용이 어떻게 달라졌는지를 남기는 편이 유용해요. 그래야 다음 달 데이터가 늘거나 바인드 값이 바뀌었을 때 같은 기준으로 다시 판단할 수 있습니다.

처음 확인한 KEY 표시가 그대로 남더라도 결과가 정확하고 읽는 비용이 허용 범위라면, 그 표시를 없애는 작업은 필요하지 않아요. 다음 점검자가 같은 입력으로 판단할 수 있도록 SQL ID와 자식 번호, 바인드 타입·값, 확인 시각을 함께 남겨 두세요.

정리 명령의 객체·권한·제약은 Oracle 19c DROP TABLE 문서에서 확인할 수 있어요.

확인한 공식 문서

기준일: 2026년 9월 17일. Oracle Database 19c 문서를 확인했으며, 실습 SQL의 실행 결과와 성능을 직접 측정한 글은 아닙니다.