Mah*_*kar 5 sql oracle performance oracle11g exadata
我的需求:找出a的前10个账户DEPT_NUM,按账号升序排列。
询问:
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;
Run Code Online (Sandbox Code Playgroud)
痕迹:
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
Run Code Online (Sandbox Code Playgroud)
指数:
上面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 参数。
感谢您的任何建议!
分析函数的性能可能取决于索引列的顺序。将索引从 更改为(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
Run Code Online (Sandbox Code Playgroud)
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;
/
Run Code Online (Sandbox Code Playgroud)
(ACCTNUM,DEPT_NUM) = 窗口排序推送排名
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)
Run Code Online (Sandbox Code Playgroud)
(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)
Run Code Online (Sandbox Code Playgroud)