我的要求:确定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 :(得分: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 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)=窗口不适用
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)