Java内存排序与oracle排序,Oracle 排序优化

2015年5月20日19:14:43 - 排序

1. 查看排序区内存的大小以及设置

实际排序所用到的内存、磁盘的统计信息:

pga_aggregate_target:此参数用来指定所有session总计可以使用最大PGA内存 olap:50% oltp:20%

sqlSQL> show parameter pga_aggre

NAME TYPE VALUE

------------------------------------ ---------------------- ------------------------------

pga_aggregate_target big integer 0

SQL> show parameter workarea_size_policy

workarea_size_policy:此参数用于开关PGA内存自动管理功能 auto:自动分配sort_area_size 属于workarea 如果需要经常排序就需要把这个值设置大点

sqlSQL> show parameter workarea_size_policy

NAME TYPE VALUE

------------------------------------ ---------------------- ------------------------------

workarea_size_policy string AUTO

select name, value from v$sysstat where name like ‘sort%’; select * from v$pgastat;

sqlSQL> select name , value from v$sysstat where name like 'sort%';

NAME VALUE

-------------------------------------------------------------------------------------------------------------------------------- ----------

sorts (memory) 4283

sorts (disk) 0

sorts (rows) 40823

2. 比较以下操作

select * from customers;

sqlSQL> set autotrace traceonly

SQL> select * from customers;

已选择55500行。

已用时间: 00: 00: 01.93

执行计划

----------------------------------------------------------

Plan hash value: 2008213504

-------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

-------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 55500 | 9810K| 406 (1)| 00:00:05 |

| 1 | TABLE ACCESS FULL| CUSTOMERS | 55500 | 9810K| 406 (1)| 00:00:05 |

-------------------------------------------------------------------------------

统计信息

----------------------------------------------------------

1 recursive calls

0 db block gets

5057 consistent gets

1455 physical reads

0 redo size

10855625 bytes sent via SQL*Net to client

41109 bytes received via SQL*Net from client

3701 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

55500 rows processed

select * from customers order by cust_last_name;

sqlSQL> select * from customers order by cust_last_name;

已选择55500行。

已用时间: 00: 00: 01.93

执行计划

----------------------------------------------------------

Plan hash value: 2792773903

----------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |

----------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 55500 | 9810K| | 2612 (1)| 00:00:32 |

| 1 | SORT ORDER BY | | 55500 | 9810K| 12M| 2612 (1)| 00:00:32 |

| 2 | TABLE ACCESS FULL| CUSTOMERS | 55500 | 9810K| | 406 (1)| 00:00:05 |

----------------------------------------------------------------------------------------

统计信息

----------------------------------------------------------

1 recursive calls

0 db block gets

1459 consistent gets

1454 physical reads

0 redo size

6278979 bytes sent via SQL*Net to client

41109 bytes received via SQL*Net from client

3701 SQL*Net roundtrips to/from client

1 sorts (memory)

0 sorts (disk)

55500 rows processed

可以看到使用order by用到了额外的12M内存

3. 在cust_last_name创建b*索引

没建索引:

sqlexplain plan for select cust_last_name from customers order by cust_last_name;

sqlSQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

------------------------------------------------------------------------------------------------------------------

Plan hash value: 2792773903

----------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |

----------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 55500 | 433K| | 610 (1)| 00:00:08 |

| 1 | SORT ORDER BY | | 55500 | 433K| 880K| 610 (1)| 00:00:08 |

| 2 | TABLE ACCESS FULL| CUSTOMERS | 55500 | 433K| | 405 (1)| 00:00:05 |

----------------------------------------------------------------------------------------

建立索引:

sqlcreate index lastname_idx on customers(cust_last_name);

sqlexplain plan for select /*+ index(c lastname_idx) */ cust_last_name from customers order by cust_last_name;

执行计划:

sqlSQL> explain plan for select /*+ index(c lastname_idx) */ cust_last_name from customers order by cust_last_name;

已解释。

已用时间: 00: 00: 00.00

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

------------------------------------------------------------------------------------------------------------------

Plan hash value: 3470560620

---------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

---------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 55500 | 433K| 143 (1)| 00:00:02 |

| 1 | INDEX FULL SCAN | LASTNAME_IDX | 55500 | 433K| 143 (1)| 00:00:02 |

---------------------------------------------------------------------------------

可以发现在一列建立索引后,对该列进行排序操作不需要再执行排序操作,

他会根据索引来进行查询(索引中本来就已经排好序)

结论

建立索引可以节省排序操作的时间。

4. 查询前十条记录

通常我们都会:

sqlselect cust_last_name from customers where rownum<=20 order by 1;

sqlSQL> select cust_last_name from customers where rownum<=20 order by 1;

CUST_LAST_NAME

--------------------------------------------------------------------------------

Everett

Everett

Everett

Everett

Everett

Everett

Everett

Everett

Everett

Ruddy

Ruddy

CUST_LAST_NAME

--------------------------------------------------------------------------------

Ruddy

Ruddy

Ruddy

Ruddy

Ruddy

Ruddy

Ruddy

Ruddy

Ruddy

已选择20行。

这样是错误的,因为在oracle中where永远都是先执行的也就先取20条再排序。

正确的做法是使用子查询:

sqlselect cust_last_name from (select * from customers order by cust_last_name) where rownum<10;

sqlSQL>select cust_last_name from (select * from customers order by cust_last_name) where rownum<10;

CUST_LAST_NAME

--------------------------------------------------------------------------------

Aaron

Aaron

Aaron

Aaron

Aaron

Aaron

Aaron

Aaron

Aaron

Aaron

Aaron

CUST_LAST_NAME

--------------------------------------------------------------------------------

Aaron

Aaron

Aaron

Aaron

Aaron

Aaron

Aaron

Aaron

Aaron

已选择20行。

没建索引:

sqlPLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------------------------------

Plan hash value: 1285511559

---------------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |

---------------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 9 | 198 | | 2612 (1)| 00:00:32 |

|* 1 | COUNT STOPKEY | | | | | | |

| 2 | VIEW | | 55500 | 1192K| | 2612 (1)| 00:00:32 |

|* 3 | SORT ORDER BY STOPKEY| | 55500 | 9810K| 12M| 2612 (1)| 00:00:32 |

| 4 | TABLE ACCESS FULL | CUSTOMERS | 55500 | 9810K| | 406 (1)| 00:00:05 |

---------------------------------------------------------------------------------------------

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter(ROWNUM<10)

3 - filter(ROWNUM<10)

已选择17行。

建立索引后:

sqlPLAN_TABLE_OUTPUT

----------------------------------------------------------------------------------------------------

Plan hash value: 3026242074

----------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

----------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 9 | 198 | 4 (0)| 00:00:01 |

|* 1 | COUNT STOPKEY | | | | | |

| 2 | VIEW | | 9 | 198 | 4 (0)| 00:00:01 |

| 3 | INDEX FULL SCAN| LASTNAME_IDX | 9 | | 2 (0)| 00:00:01 |

----------------------------------------------------------------------------------

PLAN_TABLE_OUTPUT

----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter(ROWNUM<10)

已选择15行。

建立索引后,子查询效率明显提高

同时select cust_last_name from customers where rownum<=10 order by cust_last_name;和上面的结果已经大不相同。

sqlSQL> select cust_last_name from customers where rownum<=10 order by cust_last_name;

CUST_LAST_NAME

--------------------------------------------------------------------------------

Aaron

Aaron

Aaron

Aaron

Aaron

Aaron

Aaron

Aaron

Aaron

Aaron

已选择10行。

执行计划:

sqlSQL> explain plan for

2 select cust_last_name from customers where rownum<=10 order by cust_last_name;

已解释。

已用时间: 00: 00: 00.00

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

---------------------------------------------------------------------------------------------

Plan hash value: 2820001957

---------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

---------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 10 | 80 | 2 (0)| 00:00:01 |

|* 1 | COUNT STOPKEY | | | | | |

| 2 | INDEX FULL SCAN| LASTNAME_IDX | 55500 | 433K| 2 (0)| 00:00:01 |

---------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT

---------------------------------------------------------------------------------------------

---------------------------------------------------

1 - filter(ROWNUM<=10)

已选择14行。

竟然不是刚刚那样乱的。

结论

建立索引能够对提高子查询的性能,并且查询前十条记录不再需要使用子查询, 因为建立好索引后已经是排好序的,只要根据索引从表中拿出前十条记录即可。

5. 分组与索引

首先先建立一个表

sqlSQL> create table s as select * from sales;

表已创建。

s表与sales表的数据完全是一致的但s表没有sales表上的索引。

然后我们看一下执行计划:

sqlSQL> explain plan for

2 select cust_id,avg(amount_sold) from s group by cust_id;

已解释。

已用时间: 00: 00: 00.23

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

------------------------------------------------------------------------------------

Plan hash value: 1912481676

---------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

---------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 785K| 19M| 1271 (4)| 00:00:16 |

| 1 | HASH GROUP BY | | 785K| 19M| 1271 (4)| 00:00:16 |

| 2 | TABLE ACCESS FULL| S | 785K| 19M| 1236 (1)| 00:00:15 |

---------------------------------------------------------------------------

Note

PLAN_TABLE_OUTPUT

------------------------------------------------------------------------------------

-----

- dynamic sampling used for this statement (level=2)

已选择13行。

我们再看一下sales表(即建立了索引的表):

sqlSQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------------

Plan hash value: 2820001957

---------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

---------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 10 | 80 | 2 (0)| 00:00:01 |

|* 1 | COUNT STOPKEY | | | | | |

| 2 | INDEX FULL SCAN| LASTNAME_IDX | 55500 | 433K| 2 (0)| 00:00:01 |

---------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------------

---------------------------------------------------

1 - filter(ROWNUM<=10)

已选择14行。

结论

group by的一列上建立索引group by 性能更佳。

下面是关于order by 升序降序的执行计划可以看出建立索引升降序对排序不会影响性能

升序:

sqlSQL> select cust_last_name from customers where rownum <= 10 order by cust_last_name;

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------------

Plan hash value: 2820001957

---------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

---------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 10 | 80 | 2 (0)| 00:00:01 |

|* 1 | COUNT STOPKEY | | | | | |

| 2 | INDEX FULL SCAN| LASTNAME_IDX | 55500 | 433K| 2 (0)| 00:00:01 |

---------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------------

---------------------------------------------------

1 - filter(ROWNUM<=10)

已选择14行。

降序:

sqlSQL> select cust_last_name from customers where rownum <= 10 order by cust_last_name;

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------------------------

Plan hash value: 1596600344

--------------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 9 | 72 | 2 (0)| 00:00:01 |

|* 1 | COUNT STOPKEY | | | | | |

| 2 | INDEX FULL SCAN DESCENDING| LASTNAME_IDX | 55500 | 433K| 2 (0)| 00:00:01 |

--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------------------------

---------------------------------------------------

1 - filter(ROWNUM<10)

已选择14行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值