2014-07-07 55 views
4

我的要求:确定DEPT_NUM的排名前10的帐户,由帐号按升序排序。窗口函数排序昂贵,我们可以克服它吗?

查询:

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 

指数:

index scan说,INDEX STORAGE在列DEPT_NUM

强制Full Table扫描制成成本从3855到11092

表中的行的总数为632667;


以上皆为测试区域结果。产量实际上有两倍的数量。

我的数据库是Exadata,Quarter RAC。运行Oracle 11g R2。数据库足够强大,可立即执行,但DBA不愿意使用13M的tempspc。商业报道,这份报告的频率将是每小时4次。而最主要的是,此表获取实时插入/更新的地块

我们能凑合像
1的过程)增加PGA的会话?(不知道,如果真的可能吗?)
2 )会额外索引有帮助吗?

只是想让一些不同的眼睛看到这一点,因为我们的团队完全专注于DBA参数。

感谢您的任何建议!

+0

我不确定,但会row_identifier> = 10;在这里工作得更好,因为它不必评估两种不同的东西。由于介于两者之间本质上是做<= 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 

索引快速全扫描使用速度更快的多块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 PUSHED 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

谢谢你停下来帮忙。你的解决方案很有意义,我将在我的工作场所创建索引并让你知道结果! –

相关问题