2012-09-10 4 views
3

Oracle 쿼리의 실행 계획에 대해 혼동스러워합니다. 이것은 플랫폼 IBM AIX 6.1의 Oracle Enterprise Edition 11.2.0.1.0에 있습니다. TEST1 (1 백만 행) 테이블과 TEST2 (50,000 행) 테이블이 있습니다. 두 테이블 모두 동일한 열을가집니다. 이 두 테이블의 합집합으로 생성 된 뷰가 있습니다. WHERE 절에 인덱스 된 열이있는이 뷰에 대한 쿼리를 실행하고 있습니다. 내가 찾을 수있는 것은 인덱스가 사용되지 않고 전체 테이블 스캔이 발생한다는 것입니다. 쿼리를 약간 수정하면 인덱스가 사용되기 시작했습니다. 이 특별한 변화가 어떻게 계획 변경을 초래할 수 있는지 궁금합니다.Oracle 쿼리 실행 계획

아래의 전체 DDL + DML을 찾으십시오. 나는 단순화 된 예를 제시했다. 실제 스키마와 요구 사항은 좀 더 복잡합니다. 실제로 해당 쿼리는 동적으로 생성되어 OCI 코드 생성기에 의해 실행됩니다. 여기서 의도하는 것은 대안을 얻는 것이 아니라 계획 변경의 논리적 추론 (필자는 응용 프로그램 프로그래머이고 데이터베이스 관리자가 아님)을 이해하는 것입니다. 귀하의 도움을 많이 주시면 감사하겠습니다.

DROP TABLE TEST1 CASCADE CONSTRAINTS ; 
DROP TABLE TEST2 CASCADE CONSTRAINTS ; 

CREATE TABLE TEST1 
( 
    ID  NUMBER(20)  NOT NULL, 
    NAME VARCHAR2(40), 
    DAY  NUMBER(20) 
) 
PARTITION BY RANGE (DAY) 
( 
    PARTITION P001 VALUES LESS THAN (2), 
    PARTITION P002 VALUES LESS THAN (3), 
    PARTITION P003 VALUES LESS THAN (4), 
    PARTITION P004 VALUES LESS THAN (5), 
    PARTITION P005 VALUES LESS THAN (6), 
    PARTITION P006 VALUES LESS THAN (7), 
    PARTITION P007 VALUES LESS THAN (8), 
    PARTITION P008 VALUES LESS THAN (9), 
    PARTITION P009 VALUES LESS THAN (10), 
    PARTITION P010 VALUES LESS THAN (11), 
    PARTITION P011 VALUES LESS THAN (12), 
    PARTITION P012 VALUES LESS THAN (13), 
    PARTITION P013 VALUES LESS THAN (14), 
    PARTITION P014 VALUES LESS THAN (15), 
    PARTITION P015 VALUES LESS THAN (16), 
    PARTITION P016 VALUES LESS THAN (17), 
    PARTITION P017 VALUES LESS THAN (18), 
    PARTITION P018 VALUES LESS THAN (19), 
    PARTITION P019 VALUES LESS THAN (20), 
    PARTITION P020 VALUES LESS THAN (21), 
    PARTITION P021 VALUES LESS THAN (22), 
    PARTITION P022 VALUES LESS THAN (23), 
    PARTITION P023 VALUES LESS THAN (24), 
    PARTITION P024 VALUES LESS THAN (25), 
    PARTITION P025 VALUES LESS THAN (26), 
    PARTITION P026 VALUES LESS THAN (27), 
    PARTITION P027 VALUES LESS THAN (28), 
    PARTITION P028 VALUES LESS THAN (29), 
    PARTITION P029 VALUES LESS THAN (30), 
    PARTITION P030 VALUES LESS THAN (31) 
) ; 

CREATE INDEX IX_ID on TEST1 (ID) INITRANS 4 STORAGE(FREELISTS 16) LOCAL 
( 
    PARTITION P001, 
    PARTITION P002, 
    PARTITION P003, 
    PARTITION P004, 
    PARTITION P005, 
    PARTITION P006, 
    PARTITION P007, 
    PARTITION P008, 
    PARTITION P009, 
    PARTITION P010, 
    PARTITION P011, 
    PARTITION P012, 
    PARTITION P013, 
    PARTITION P014, 
    PARTITION P015, 
    PARTITION P016, 
    PARTITION P017, 
    PARTITION P018, 
    PARTITION P019, 
    PARTITION P020, 
    PARTITION P021, 
    PARTITION P022, 
    PARTITION P023, 
    PARTITION P024, 
    PARTITION P025, 
    PARTITION P026, 
    PARTITION P027, 
    PARTITION P028, 
    PARTITION P029, 
    PARTITION P030 
) ; 

CREATE TABLE TEST2 
( 
    ID  NUMBER(20)  PRIMARY KEY NOT NULL, 
    NAME VARCHAR2(40), 
    DAY  NUMBER(20) 
) ; 

CREATE OR REPLACE VIEW TEST_V AS 
SELECT 
    ID, NAME, DAY 
FROM 
    TEST1 
UNION 
SELECT 
    ID, NAME, DAY 
FROM 
    TEST2 ; 

begin 
    for count in 1..1000000 
    loop 
     insert into test1 values(count, 'John', mod(count, 30) + 1) ; 
    end loop ; 
end ; 
/ 

begin 
    for count in 1000000..1050000 
    loop 
     insert into test2 values(count, 'Mary', mod(count, 30) + 1) ; 
    end loop ; 
end ; 
/ 

commit ; 

set lines 300 ; 
set pages 1000 ; 

-- Actual query 
explain plan for 
    SELECT Key FROM 
    ( 
     WITH recs AS 
     ( 
      SELECT * FROM TEST_V WHERE ID = 70000 
     ) 
     ( 
      SELECT 1 AS Key FROM recs WHERE NAME = 'John' 
     ) 
     UNION 
     ( 
      SELECT 2 AS Key FROM recs WHERE NAME = 'Mary' 
     ) 
    ) ; 

select * from table(dbms_xplan.display()) ; 

PLAN_TABLE_OUTPUT 
------------------------------------------------------------------------------------------------------------------------------------------ 
| Id | Operation     | Name       | Rows | Bytes | TempSpc | Cost (%CPU) | Time | Pstart | Pstop | 
------------------------------------------------------------------------------------------------------------------------------------------ 
| 0 | SELECT STATEMENT   |        | 1611K | 4721K |   | 13559 (1) | 00:02:43 |  |  | 
| 1 | VIEW      |        | 1611K | 4721K |   | 13559 (1) | 00:02:43 |  |  | 
| 2 | TEMP TABLE TRANSFORMATION |        |  |  |   |    |   |  |  | 
| 3 | LOAD AS SELECT   | SYS_TEMP_0FD9D6610_34D3B6C |  |  |   |    |   |  |  | 
|* 4 |  VIEW     | TEST_V      | 805K | 36M |   | 10403 (1) | 00:02:05 |  |  | 
| 5 |  SORT UNIQUE   |        | 805K | 36M | 46M | 10403 (8) | 00:02:05 |  |  | 
| 6 |  UNION-ALL    |        |  |  |   |    |   |  |  | 
| 7 |  PARTITION RANGE ALL |        | 752K | 34M |   | 721 (1) | 00:00:09 | 1 | 30 | 
| 8 |  TABLE ACCESS FULL  | TEST1      | 752K | 34M |   | 721 (1) | 00:00:09 | 1 | 30 | 
| 9 |  TABLE ACCESS FULL | TEST2      | 53262 | 2496K |   | 68 (0)  | 00:00:01 |  |  | 
| 10 | SORT UNIQUE    |        | 1611K | 33M | 43M | 13559 (51) | 00:02:43 |  |  | 
| 11 |  UNION-ALL    |        |  |  |   |    |   |  |  | 
|* 12 |  VIEW     |        | 805K | 16M |   | 1429 (1) | 00:00:18 |  |  | 
| 13 |  TABLE ACCESS FULL  | SYS_TEMP_0FD9D6610_34D3B6C | 805K | 36M |   | 1429 (1) | 00:00:18 |  |  | 
|* 14 |  VIEW     |        | 805K | 16M |   | 1429 (1) | 00:00:18 |  |  | 
| 15 |  TABLE ACCESS FULL  | SYS_TEMP_0FD9D6610_34D3B6C | 805K | 36M |   | 1429 (1) | 00:00:18 |  |  | 
------------------------------------------------------------------------------------------------------------------------------------------ 

Predicate Information (identified by operation id): 
--------------------------------------------------- 
    4 - filter("ID"=70000) 
    12 - filter("NAME"='John') 
    14 - filter("NAME"='Mary') 


-- Modified query (only change is absence of outermost SELECT) 
explain plan for 
    WITH recs AS 
    ( 
     SELECT * FROM TEST_V WHERE ID = 70000 
    ) 
    ( 
     SELECT 1 AS Key FROM recs WHERE NAME = 'John' 
    ) 
    UNION 
    ( 
     SELECT 2 AS Key FROM recs WHERE NAME = 'Mary' 
    ) ; 

select * from table(dbms_xplan.display()) ; 

PLAN_TABLE_OUTPUT 
----------------------------------------------------------------------------------------------------------------------------------------- 
| Id | Operation        | Name      | Rows | Bytes | Cost (%CPU) | Time  | Pstart | Pstop | 
----------------------------------------------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT       |       | 4 | 88 | 6 (67) | 00:00:01 |  |  | 
| 1 | TEMP TABLE TRANSFORMATION    |       |  |  |    |   |  |  | 
| 2 | LOAD AS SELECT       | SYS_TEMP_0FD9D6611_34D3B6C |  |  |    |   |  |  | 
| 3 | VIEW         | TEST_V      | 2 | 96 | 4 (50) | 00:00:01 |  |  | 
| 4 |  SORT UNIQUE       |       | 2 | 96 | 4 (75) | 00:00:01 |  |  | 
| 5 |  UNION-ALL       |       |  |  |    |   |  |  | 
| 6 |  PARTITION RANGE ALL    |       | 1 | 48 | 1 (0) | 00:00:01 | 1 | 30 | 
| 7 |  TABLE ACCESS BY LOCAL INDEX ROWID | TEST1      | 1 | 48 | 1 (0) | 00:00:01 | 1 | 30 | 
|* 8 |  INDEX RANGE SCAN      | IX_ID      | 1 |  | 1 (0) | 00:00:01 | 1 | 30 | 
| 9 |  TABLE ACCESS BY INDEX ROWID  | TEST2      | 1 | 48 | 1 (0) | 00:00:01 |  |  | 
|* 10 |  INDEX UNIQUE SCAN     | SYS_C001242692    | 1 |  | 1 (0) | 00:00:01 |  |  | 
| 11 | SORT UNIQUE       |       | 4 | 88 | 6 (67) | 00:00:01 |  |  | 
| 12 | UNION-ALL        |       |  |  |    |   |  |  | 
|* 13 |  VIEW         |       | 2 | 44 | 2 (0) | 00:00:01 |  |  | 
| 14 |  TABLE ACCESS FULL     | SYS_TEMP_0FD9D6611_34D3B6C | 2 | 96 | 2 (0) | 00:00:01 |  |  | 
|* 15 |  VIEW         |       | 2 | 44 | 2 (0) | 00:00:01 |  |  | 
| 16 |  TABLE ACCESS FULL     | SYS_TEMP_0FD9D6611_34D3B6C | 2 | 96 | 2 (0) | 00:00:01 |  |  | 
----------------------------------------------------------------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 
    8 - access("ID"=70000) 
    10 - access("ID"=70000) 
    13 - filter("NAME"='John') 
    15 - filter("NAME"='Mary') 

quit ; 

감사에게 & 관련,
Reji

+2

[sqlfiddle] (http://sqlfiddle.com/#!4/c91d7/1)에서이 문제를 재현했습니다 : –

+0

설명 플랜에서 모든 결과를 제공 했습니까? –

+1

감사합니다. Florin. 처음으로이 사이트 (sqlfiddle)를보고 있습니다. 내가 알았 더라면 샘플을 만들었을 것이다. 게시하기 전에 계획을 형식화하는 데 거의 30 분이 걸렸습니다. (그래픽 계획도 너무 멋지고 유용합니다.) – mpathi

답변

2

내가 아닌 다른이 문제에 대한 논리적 설명이 생각하지 않습니다, 11.2.0.3에서이 문제를 재현 할 수 버그에 충돌이, 그 11.2.0.3에서는 분명히 해결됩니다.

내 눈에 즉시 뛰어 올랐던 한 가지는 객체 통계가 부족하고 OPTIONMIZER_DYNAMIC_SAMPLING이 0으로 설정되었다는 사실입니다. OPTIMIZER_DYNAMIC_SAMPLING = 2로 재현 해 볼 수 있습니다. 이 경우 객체 통계가 누락되면 동적 샘플러가 실행됩니다. BTW : 올바른 옵티 마이저 통계 대신이 기능을 사용하지 마십시오. 동적 샘플링에 대한 추가 정보 Dynamic sampling and its impact on the Optimizer

문서화 된 질문 및 스크립트/테스트 케이스에서는 추가 및 nologging을 시도합니다. 이 옵션은 대량 삽입의 경우에만 작동하며 값이있는 행 삽입의 경우에는 작동하지 않습니다. 모든 삽입물에 대해 일어나는 일은 다음과 같습니다. 하이 워터 마크를 밀어 올리고 프리 블록에 데이터 블록 전체를 덤프합니다.이 경우 한 행만 있으면됩니다. 데이터베이스는이 명령을 무시합니다.

SQL을 테이블에 적용하기 전에 옵티 마이저 통계를 제공하는지 확인하십시오. 이것은 분명히 당신의 사건을 도울 것입니다.

+0

감사합니다. ik_zelf. 계획서가 완료되었습니다. 또한 계획 아래의 "메모"에 동적 샘플링 2) 사용됩니다. 나는 또한 11.2.0.3.0 시도해 줄 것입니다./* + 추가 */힌트 및 nologging, 정정 주셔서 감사합니다. 내 상자에 쿼리 및 데이터의 다양한 조합을 시도했다 이 실험에서 생성 된 로그는 피하고 싶었습니다. 빠른 검색 결과는이 힌트를 제시했으며 스파이크 코드이므로 유효성 검사를 거치지 않았습니다. – mpathi