Oracle 排序優化

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

1. 查看排序區內存的大小以及設置

實際排序所用到的內存、磁盤的統計信息:session

pga_aggregate_target:此參數用來指定全部session總計可使用最大PGA內存 olap:50% oltp:20%oracle

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 若是須要常常排序就須要把這個值設置大點ide

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;this

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;code

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內存orm

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行。
相關文章
相關標籤/搜索