2012-02-10 4 views
1

에 의해 영감을 얻었습니다 rank() 함수를 테스트하여 하위 쿼리가 순위보다 비효율적인지 확인하려고했습니다.성능 : 순위() 대 하위 쿼리. 하위 쿼리 비용이 저렴합니까?

select * 
    from teste_rank r 
where r.data_mov = (select max(data_mov) 
         from teste_rank 
         where data_mov <= trunc(sysdate) 
         and codigo = 1) 
    and r.codigo = 1; 

Explain Plan for sub query


select * 
    from (select rank() over (partition by codigo order by data_mov desc) rn, t.* 
      from teste_rank t 
      where codigo = 1 
      and data_mov <= trunc(sysdate)) r 
where r.rn = 1; 
: 다음
declare 
    vdata date; 
begin 
    dbms_random.initialize(120401); 
    vdata := to_date('04011997','DDMMYYYY'); 
    for reg in 1 .. 465 loop 
    vdata := to_date('04011997','DDMMYYYY'); 
    while vdata <= trunc(sysdate) loop 
     insert into teste_rank 
      (codigo, data_mov, valor) 
     values 
      (reg, vdata, dbms_random.value(1,150000)); 
     vdata := vdata + 2; 
    end loop; 
    commit; 
    end loop; 
end; 
/

그리고

두 querys 테스트를 몇 가지 기록을 ...

create table teste_rank (codigo number(7), data_mov date, valor number(14,2)); 
alter table teste_rank add constraint tst_rnk_pk primary key (codigo, data_mov); 

삽입 : 그래서 테이블을 생성

Explain plan rank()

하위 쿼리의 비용은 rank()보다 낮습니다. 이게 옳은 거니? 거기에 뭔가 빠졌나요?

추신 : 또한 테이블의 전체 쿼리와 저렴한 비용의 하위 쿼리로 테스트되었습니다.

편집

나는 두 쿼리의 TKPROF 생성 (하나를 추적, 종료 데이터베이스, 시작을 두 번째 추적). rank()

call  count  cpu elapsed  disk  query current  rows 
------- ------ -------- ---------- ---------- ---------- ---------- ---------- 
Parse  1  0.00  0.02   3   3   0   0 
Execute  1  0.00  0.00   0   0   0   0 
Fetch  2  0.00  0.00   9   19   0   1 
------- ------ -------- ---------- ---------- ---------- ---------- ---------- 
total  4  0.01  0.03   12   22   0   1 

를 들어 하위 쿼리

call  count  cpu elapsed  disk  query current  rows 
------- ------ -------- ---------- ---------- ---------- ---------- ---------- 
Parse  1  0.00  0.02   3   5   0   0 
Execute  1  0.00  0.00   0   3   0   0 
Fetch  2  0.00  0.00   1   4   0   1 
------- ------ -------- ---------- ---------- ---------- ---------- ---------- 
total  4  0.00  0.02   4   12   0   1 

를 들어

나는 순위에 비해는 항상 덜 효율적이지 그 하위 쿼리를 결론을 내릴 수 있습니까? 하위 쿼리 대신 순위가 표시되면?

+0

테이블과 색인을 분석 했습니까? –

+0

(이 방법이 작동하는지, 아니면 일부 규칙에 위배되는지는 확실하지 않습니다.) @Justin Cave,이 퀘스트는 다른 게시물의 답변과 관련되어 있으니 알려 주시고 의견을 제시해주십시오. –

답변

2

귀하의 질문이 무엇인지 잘 모르겠습니다. 예,이 두 실행 계획에 따르면 하위 쿼리 방법의 예상 비용이 낮습니다. 너무 놀랍지는 않습니다. 관심있는 정확한 행을 찾기 위해 인덱스를 사용할 수 있기 때문입니다.이 경우 특히 하위 쿼리는 PK 인덱스를 매우 빠르게 검사해야합니다. 부속 조회가 색인의 일부가 아닌 열을 포함하면 상황이 다를 수 있습니다.

rank()을 사용하는 쿼리는 일치하는 모든 행을 가져와 순위를 지정해야합니다. 필자는 옵티 마이저가 이것이 최상위 n 쿼리임을 인식하여 모든 정렬을 피하는 단락 회로 로직을 가지고 있다고 생각하지 않습니다.

또한 옵티마이 저가 top-n 쿼리로 인식해야하는이 양식을 사용해보십시오. 난 당신의 경우에 테이블 액세스가 이어지는 인덱스에 대한 단일 범위 스캔 만 필요하다고 기대할 것입니다.

select * 
    from (select * 
      from teste_rank r 
      where data_mov <= trunc(sysdate) 
      and codigo = 1 
     order by data_mov desc) 
    where rownum=1; 
+0

내가 언급 한 질문에서 대답 중 하나는'sub query'가'rank()'보다 비효율적이지 않다고 답합니다. 나는 그것을 확인하려고 노력하고있다. –

+2

@ SérgioMichels : 나는 당신의 테스트가 rank() 메서드가 서브 쿼리 메서드보다 항상 효율적이지는 않다는 것을 증명한다고 말할 수 있습니다. 두 가지 모두 원하는 결과를 얻는 데 사용하는 합리적인 기술이며, 어느 것이 더 효율적인지는 관련된 열, 인덱스 방법, 데이터 크기 및 분포와 같은 여러 요소에 따라 달라집니다. 귀하의 경우, 서브 u 리는 인덱스에서 다루는 컬럼을 정확히 사용할 수 있고 인덱스 항목의 순서를 이용하여 추가 정렬을 피할 수 있으므로 매우 효율적입니다. 다른 경우에는 이것이 사실이 아닙니다. –

2

비용은 쿼리를 실행하는 데 필요한 비용 기반 옵티 마이저 추정입니다.

특히 통계가 오래되면 CBO가 잘못 처리하는 경우가 있습니다.

그럼, 어떻게해야합니까? 'autotrace on'으로 각 쿼리를 실행 해보십시오. 각 쿼리는 얼마나 많은 버퍼 가져 오기 및 실제 읽기를 수행합니까? 즉, 실제 작품이 얼마나 많은 쿼리를 수행합니까?

희망이 있습니다.

+0

물론 물리적 읽기를 살펴보면 캐시가 작동 할 수 있습니다. –

+0

@DaveCosta 어떻게 쿼리 캐시를 피할 수 있습니까? –

+0

@ Mark J. Bobak, 답변 해 주신 데 대해 감사 드리며, tkprof의 결과로 내 질문을 업데이트하고 질문에 대해 더 자세히 설명하려고 시도했습니다. 대답에 새로운 것을 추가해 주실 수 있습니까? 다시 고마워요 :) –