2013-11-26 6 views
4

우리가 두 개의 테이블이 다음과 같은 방법으로 테스트하고 TEST_CHILDS을 말해봐 존재 :개선 SQL 확장 성

creat TABLE TEST(id1 number PRIMARY KEY, word VARCHAR(50),numero number); 
creat TABLE TEST_CHILD (id2 number references test(id), word2 VARCHAR(50)); 

CREATE INDEX TEST_IDX ON TEST_CHILD(word2); 
CREATE INDEX TEST_JOIN_IDX ON TEST_CHILD(id); 

insert into TEST SELECT ROWNUM,U1.USERNAME||U2.TABLE_NAME, LENGTH(U1.USERNAME) FROM ALL_USERS U1,ALL_TABLES U2; 
INSERT INTO TEST_CHILD SELECT MOD(ROWNUM,15000)+1,U1.USER_ID||U2.TABLE_NAME FROM ALL_USERS U1,ALL_TABLES U2; 

우리는 자식 테이블에 몇 가지 기준을 만족 TEST 테이블에서 행을 얻을 조회하고 싶은, 그래서 우리 다음을 참조하십시오 :

SELECT /*+FIRST_ROWS(10)*/* FROM TEST T WHERE EXISTS (SELECT NULL FROM TEST_CHILD TC WHERE word2 like 'string%' AND TC.id = T.id) AND ROWNUM < 10; 

우리는 항상 처음 10 개의 결과를 원합니다. 따라서 테이블에 10 개의 일치하는 값 또는 1,000,000의 테이블이 있는지에 관계없이 10 개의 결과를 읽는 데 동일한 응답 시간을 사용하고 싶습니다. 그것은 자식 테이블에서 10 개의 다른 결과를 얻을 수 있고 부모 테이블에 값을 가져올 수 있기 때문입니다 (또는 적어도 그것이 우리가 원하는 계획입니다). 실제 실행 계획을 점검 할 때 그러나 우리는 다음을 참조하십시오 STOPKEY에서

----------------------------------------------------------------------------------------------- 
| Id | Operation      | Name  | Rows | Bytes | Cost (%CPU)| Time  | 
----------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT    |    |  1 | 54 |  5 (20)| 00:00:01 | 
|* 1 | COUNT STOPKEY     |    |  |  |   |   | 
| 2 | NESTED LOOPS     |    |  |  |   |   | 
| 3 | NESTED LOOPS     |    |  1 | 54 |  5 (20)| 00:00:01 | 
| 4 |  SORT UNIQUE     |    |  1 | 23 |  3 (0)| 00:00:01 | 
| 5 |  TABLE ACCESS BY INDEX ROWID| TEST_CHILD |  1 | 23 |  3 (0)| 00:00:01 | 
|* 6 |  INDEX RANGE SCAN   | TEST_IDX |  1 |  |  2 (0)| 00:00:01 | 
|* 7 |  INDEX UNIQUE SCAN   | SYS_C005145 |  1 |  |  0 (0)| 00:00:01 | 
| 8 | TABLE ACCESS BY INDEX ROWID | TEST  |  1 | 31 |  1 (0)| 00:00:01 | 
----------------------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - filter(ROWNUM<10) 
    6 - access("WORD2" LIKE 'string%') 
     filter("WORD2" LIKE 'string%') 
    7 - access("TC"."ID"="T"."ID") 

SORT UNIQUE, 어떤 AFAIK가 마침내 첫 번째를 선택 별개을, 자식 테이블의 모든 결과를 읽는 만드는 것을 의미한다 10, 쿼리를 우리가 원하는 것처럼 확장하지 않습니다.

예제에 어떤 실수가 있습니까?

이 실행 계획을 개선하여 확장 성을 향상시킬 수 있습니까?

답변

1

SORT UNIQUE는 TEST_CHILD에서 'string %'과 일치하는 모든 레코드를 찾고 정렬합니다. 하위 테이블의 모든 결과를 읽지는 않습니다. 당신의 논리는 이것을 요구합니다. 'string %'과 일치하는 TEST_CHILD에서 처음 10 개의 행만을 선택하고 10 개의 행 모두에 동일한 ID가있는 경우 TEST의 최종 결과는 1 행만 갖습니다.

어쨌든 'string %'이 (가) TEST_CHILD의 비교적 적은 수의 행과 일치하는 한 실적은 좋을 것입니다. 'string %'가 TEST_CHILD의 HUGE 레코드 수와 종종 일치하는 상황 인 경우 현재 테이블에서 SQL을 더 성능있게 만들 수있는 방법은 많지 않습니다. 이 경우 미션 크리티컬 한 SQL이라면 연간 보너스와 연계 된 성과가 있습니다. MATERIALIZED VIEWs로 할 수있는 멋진 발놀림이있을 것입니다. TEST_CHILD에서 상위 카디 낼 리티 WORD2 값에 대해 10 개의 테스트 행을 사전 계산하십시오.

SELECT * 
FROM TEST 
WHERE ID1 IN 
      (SELECT ID2 
      FROM TEST_CHILD 
      WHERE word2 like 'string%' 
        AND ROWNUM < 1000) 
     AND ROWNUM <10; 

당신은 조정할 수 있습니다 : -

마지막으로 생각 같은 TEST 행을 일치 TEST_CHILD 행의 수천이없는 경우 작동해야 "위험"솔루션, 그러나 사람은 다음과 같이 될 것이다 1000 위나 아래이지만, 너무 낮 으면 10 개 미만의 ID 값을 찾을 위험이 있습니다. 그러면 10 개 미만의 행으로 최종 결과를 얻을 수 있습니다.

+1

"이 보너스를 생각해 보면 보너스가 있지만, 1000 명의 어린이가 위험한 방법보다 훨씬 뛰어납니다. PL/SQL로이 문제를 해결할 수 있습니다. 쿼리하는 함수를 작성할 수 있습니다. 일치하는 입력 'string %'매개 변수에 대한 TEST_CHILD, 결과를 스풀링하고 10 개의 고유 ID가 발견 될 때까지 ID 대기열에 넣은 다음 10 개의 고유 ID 배열을 리턴합니다. – KevinKirkpatrick