2014-07-07 3 views
4

내 요구 사항 :DEPT_NUM의 상위 10 개 계정을 계정 번호순으로 오름차순으로 나열하십시오.창 함수 SORT 비용이 많이 들지만 극복 할 수 있습니까?

검색어 :

SELECT * FROM 
(
    select acctnum,dept_num,row_number() OVER (PARTITION BY DEPT_NUM ORDER BY ACCTNUM) as row_identifier 
    FROM MYTABLE 
) 
WHERE row_identifier between 1 and 10; 

추적 :

7532 rows selected. 


Execution Plan 
---------------------------------------------------------- 
Plan hash value: 1480074522 

-------------------------------------------------------------------------------------------- 
| Id | Operation    | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time  | 
-------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT   |   | 577K| 15M|  | 3855 (1)| 00:00:47 | 
|* 1 | VIEW     |   | 577K| 15M|  | 3855 (1)| 00:00:47 | 
|* 2 | WINDOW SORT PUSHED RANK|   | 577K| 7890K| 13M| 3855 (1)| 00:00:47 | 
| 3 | INDEX FAST FULL SCAN | IMTAB05 | 577K| 7890K|  | 987 (1)| 00:00:12 | 
-------------------------------------------------------------------------------------------- 

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

    1 - filter("ROW_IDENTIFIER">=1 AND "ROW_IDENTIFIER"<=5) 
    2 - filter(ROW_NUMBER() OVER (PARTITION BY "DEPT_NUM" ORDER BY "ACCTNUM")<=5) 


Statistics 
---------------------------------------------------------- 
      0 recursive calls 
      2 db block gets 
     4298 consistent gets 
      0 physical reads 
      0 redo size 
    144367 bytes sent via SQL*Net to client 
     486 bytes received via SQL*Net from client 
      3 SQL*Net roundtrips to/from client 
      1 sorts (memory) 
      0 sorts (disk) 
     7532 rows processed 

색인 : 열 DEPT_NUM

index scan는 말한다, INDEX STORAGE.

3855에서 테이블의 행 11,092

총에 Full Table 스캔 만들어 비용을 강제는 632,667이며,


위의 모든 테스트 영역 결과입니다. 생산량은 실제로 두 배입니다.

내 데이터베이스는 Exadata, Quarter RAC입니다. Oracle 11g R2를 실행 중입니다. 데이터베이스는 즉시 실행하기에 충분히 강력하지만 DBA는 13M의 tempSpc에 주저했습니다. 사업 보고서에 따르면이 보고서의 빈도는 한 시간에 4 번입니다. 그리고 중요한 것은 그것이 정말 가능하다면이 테이블은,

우리가
1과 같은 과정을 즉석에서 할 수

) 세션의 PGA 증가? (확실하지 실시간 삽입/업데이트를 많이 얻을 수있다?)
2) 추가 색인이 도움이됩니까?

우리 그룹이 완전히 DBA 매개 변수에만 초점을 맞추기 때문에 다른 시각으로보고 싶습니다.

의견을 보내 주셔서 감사합니다.

+0

잘 모르겠지만 row_identifier> = 10; 그것은 두 가지 다른 것으로 평가할 필요가 없기 때문에 여기서 더 잘 작동합니다. between 문은 본질적으로 <= 1 and a > = 10입니다. – Phil

+0

tempSpc에 허용되는 값은 무엇입니까? –

+0

http://dba.stackexchange.com/에서 DBA 조언을 요청할 수도 있습니다. –

답변

1

분석 함수의 성능은 인덱스 열 순서에 따라 달라질 수 있습니다. (ACCTNUM,DEPT_NUM)에서 (DEPT_NUM,ACCTNUM)으로 색인을 변경하면 비용이 절감되고 임시 테이블 공간이 필요하지 않게됩니다.

partition by COL_2 order by COL_1 => INDEX FAST FULL SCAN|WINDOW SORT PUSHED RANK 
partition by COL_1 order by COL_2 => INDEX FULL SCAN|WINDOW NOSORT 

INDEX FAST FULL SCAN 빠른 멀티 블록 IO를 사용하지만 그것은 또한 정렬 영역에 대한 데이터와 가능성이 임시 테이블을 정렬해야합니다.

INDEX FULL SCAN은 느린 단일 블록 IO를 사용하지만 데이터를 순서대로 반환하고 정렬을 피합니다.

샘플 스키마 및 데이터

--drop table mytable; 
create table mytable(dept_num number not null, acctnum number not null 
    ,a number, b number, c number, d number, e number); 
insert into mytable 
select 1 dept_num, 1 acctnum, 0,0,0,0,0 from dual union all 
select 1 dept_num, 2 acctnum, 0,0,0,0,0 from dual union all 
select 1 dept_num, 3 acctnum, 0,0,0,0,0 from dual union all 
select 2 dept_num, 1 acctnum, 0,0,0,0,0 from dual union all 
select 2 dept_num, 2 acctnum, 0,0,0,0,0 from dual union all 
select 3 dept_num, 1 acctnum, 0,0,0,0,0 from dual; 
--Create 600K similar rows. 
insert into mytable 
    select dept_num + rownumber*3, acctnum, a,b,c,d,e 
    from mytable 
    cross join (select level rownumber from dual connect by level <= 100000); 
begin 
    dbms_stats.gather_table_stats(user, 'mytable'); 
end; 
/

(ACCTNUM, DEPT_NUM) = WINDOW SORT 푸시 됨 RANK

create index mytable_idx on mytable(acctnum, dept_num); 

explain plan for 
select dept_num, acctnum from 
(
    select dept_num, acctnum 
     ,row_number() over (partition by dept_num order by acctnum) as row_identifier 
    from mytable 
) 
where row_identifier between 1 and 10; 

select * from table(dbms_xplan.display); 

Plan hash value: 952182109 

------------------------------------------------------------------------------------------------ 
| Id | Operation    | Name  | Rows | Bytes |TempSpc| Cost (%CPU)| Time  | 
------------------------------------------------------------------------------------------------ 
| 0 | SELECT STATEMENT   |    | 600K| 22M|  | 1625 (3)| 00:00:23 | 
|* 1 | VIEW     |    | 600K| 22M|  | 1625 (3)| 00:00:23 | 
|* 2 | WINDOW SORT PUSHED RANK|    | 600K| 4687K| 9424K| 1625 (3)| 00:00:23 | 
| 3 | INDEX FAST FULL SCAN | MYTABLE_IDX | 600K| 4687K|  | 239 (3)| 00:00:04 | 
------------------------------------------------------------------------------------------------ 

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

    1 - filter("ROW_IDENTIFIER">=1 AND "ROW_IDENTIFIER"<=10) 
    2 - filter(ROW_NUMBER() OVER (PARTITION BY "DEPT_NUM" ORDER BY "ACCTNUM")<=10) 

(DEPT_NUM, ACCTNUM) = WINDOW NOSORT

drop index mytable_idx; 
create index mytable_idx on mytable(dept_num, acctnum); 

explain plan for 
select dept_num, acctnum from 
(
    select dept_num, acctnum 
     ,row_number() over (partition by dept_num order by acctnum) as row_identifier 
    from mytable 
) 
where row_identifier between 1 and 10; 

select * from table(dbms_xplan.display); 

Plan hash value: 1773829932 

--------------------------------------------------------------------------------- 
| Id | Operation   | Name  | Rows | Bytes | Cost (%CPU)| Time  | 
--------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |    | 600K| 22M| 792 (2)| 00:00:12 | 
|* 1 | VIEW    |    | 600K| 22M| 792 (2)| 00:00:12 | 
|* 2 | WINDOW NOSORT |    | 600K| 4687K| 792 (2)| 00:00:12 | 
| 3 | INDEX FULL SCAN| MYTABLE_IDX | 600K| 4687K| 792 (2)| 00:00:12 | 
--------------------------------------------------------------------------------- 

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

    1 - filter("ROW_IDENTIFIER">=1 AND "ROW_IDENTIFIER"<=10) 
    2 - filter(ROW_NUMBER() OVER (PARTITION BY "DEPT_NUM" ORDER BY 
       "ACCTNUM")<=10) 
+0

도와 줘서 고맙습니다. 그리고 당신의 솔루션은 의미가 있습니다. 저는 제 직장에서 색인을 만들어 결과를 알려줄 것입니다! –