本文轉自ITPUB的anlinew。
原文出處:點擊打開鏈接
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
比較愚鈍,從事調優工作這麼些年,處理過的性能問題也不少,也就總結出這麼個公式來
S指sql所需訪問的資源總量,V指sql單位時間所能訪問的資源量,T自然就是SQL執行所需時間了
這個公式很簡單,調優的目標是減少T,T=S/V,那麼我們要調的對象自然就要放到這裏的S和V上,調優的方法就是圍繞減少S和增大V
增大V(單位時間所能訪問的資源量),在硬件設備不變的情況下所能做的只有充分利用現有資源,如:通過調整SGA充分利用物理MEMORY,通過並行處理充分利用CPU,通過調整IO分佈充分利用硬盤處理能力,還有。。。。升級設備?
減少S(sql所需訪問的資源總量),這通常是調優工作的重中之重,SQL調優的主要目的就是圍繞着如何減少S在進行,在ORACLE中,所需訪問的資源以block記,一條SQL執行所讀寫的block數直接影響到SQL的執行時間,如何知道SQL執行所讀寫的block數呢,簡單的方法如下:
set autotrace traceonly
SQL> select count(*) from test;
已用時間: 00: 00: 10.01
執行計劃
----------------------------------------------------------
Plan hash value: 1950795681
-------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 19342 (1)| 00:03:53 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| TEST | 5285K| 19342 (1)| 00:03:53 |
-------------------------------------------------------------------
統計信息
----------------------------------------------------------
204 recursive calls
0 db block gets
70655 consistent gets
70616 physical reads
0 redo size
422 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
1 rows processed
通過上面的信息我們可以看到此SQL訪問的block數爲70655,並且基本上是物理讀,其執行時間爲00: 00: 10.01
大家可能一眼就看出來了,這條SQL執行了全表掃描,加索引優化就可以了,沒錯,索引訪問正是減少SQL所需訪問資源的一個主要途徑
其效果也很明顯
已用時間: 00: 00: 01.89
執行計劃
----------------------------------------------------------
Plan hash value: 826211483
-------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3089 (2)| 00:00:38 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| I_TEST1 | 5285K| 3089 (2)| 00:00:38 |
-------------------------------------------------------------------------
統計信息
----------------------------------------------------------
1 recursive calls
0 db block gets
11218 consistent gets
11197 physical reads
0 redo size
422 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
其訪問的block數變爲11218,其執行時間隨之變爲00: 00: 01.89
通過減少S,我們可以看到T得到明顯的減小
上面情況是在V不變的情況下(都是物理讀)的差別
再看看V最大化的結果
SQL> select count(*) from test;
執行計劃
----------------------------------------------------------
Plan hash value: 826211483
-------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3089 (2)| 00:00:38 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| I_TEST1 | 5285K| 3089 (2)| 00:00:38 |
-------------------------------------------------------------------------
統計信息
----------------------------------------------------------
0 recursive calls
0 db block gets
11218 consistent gets
0 physical reads
0 redo size
422 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
已用時間: 00: 00: 00.79
SQL> select /*+parallel(test 2)*/ count(*) from test;
執行計劃
----------------------------------------------------------
Plan hash value: 826211483
-------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3089 (2)| 00:00:38 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| I_TEST1 | 5285K| 3089 (2)| 00:00:38 |
-------------------------------------------------------------------------
統計信息
----------------------------------------------------------
1 recursive calls
0 db block gets
11218 consistent gets
0 physical reads
0 redo size
422 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
已用時間: 00: 00: 00.68
T被控制到了秒以下。
可是對於這樣的一個業務11218個block的資源需求量是否也不是很合理呢,如果這個業務發生的很頻繁,每次執行都需要重複掃描到相同資源並且這部分資源佔總資源的絕大部分,這肯定也是很不合理的。
既然是減少S,那麼減少這些重複訪問的絕大部分資源理應得到更好的效果。
以上面的業務爲例:
本業務的需求是實時統計表內的行數,數據都是具有生命週期的,通常情況下一個業務表內的數據大多是處於不活動狀態,如此以來,預先統計好這部分數據並形成結果,每次需要統計這部分數據時直接調用結果必將大幅減少業務所需訪問的資源
如本例,已知object_id小於等於13000的數據處於不活動狀態
構建分析結果表
create table test_analyzed as select count(*) o_count,13000 as o_data from test where object_id<=13000;
SQL> select o_count from test_analyzed;
O_COUNT
----------
5242624
已用時間: 00: 00: 00.00
統計信息
----------------------------------------------------------
0 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
421 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> select count(*) from test where object_id>13000;
COUNT(*)
----------
42624
已用時間: 00: 00: 00.01
執行計劃
----------------------------------------------------------
Plan hash value: 3544821501
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 | 159 (1)| 00:00:02 |
| 1 | SORT AGGREGATE | | 1 | 5 | | |
|* 2 | INDEX RANGE SCAN| I_TEST1 | 73774 | 360K| 159 (1)| 00:00:02 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID">13000)
統計信息
----------------------------------------------------------
1 recursive calls
0 db block gets
98 consistent gets
0 physical reads
0 redo size
421 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
S變成了3+98=101,T自然也就變成不到10毫秒了
當然現實工作中,業務需求不可能就可以如此簡單的加以分解,這裏只是提供一個思路
性能調優是產品全生命週期的工作,一條sql的調優很可能會追溯到產品需求的定義及產品設計等環節
而在調優工作中V的提升通常是不可持續的,一定程度的提升後再想有所提高是需要付出財力的,S的提升卻是很有潛力可挖的。
個人愚見,歡迎拍磚