oracle學習筆記 如何設置shared pool及sga的大小

oracle學習筆記

如何設置shared pool及sga的大小

前面講了很多關於shared pool的知識
對我們來講最簡單最直接的工作是
sharedpool到底該設多大

一)shared pool大的壞處

有人說數據庫所在的服務器物理內存很大
可以把sharedpool設的很大

理論上講一個數據庫所要執行的sql語句是無限的
這樣就需要一個無限的shared_pool去存儲sql語句和它的執行計劃
而我們使用的內存總是有限的
從這方面講其值設的再大也會出現4031錯誤

另一方面sharedpool設大了也有壞處
分析一下
1、第一種壞處
sharedpool裏面有free空間、librarycache和rowcache

數據庫運行時有時硬解析非常多
硬解析多意味着
sql語句來了,我拿着sql語句到librarycache去找又沒有找着
沒有找着就解析
解析完了以後還需要到free裏面找空的chunk把解析的結果寫進去
再把它掛到librarycache上
整個過程非常複雜
第一要找
第二要找空的
第三把解析後的內容寫到空的上,再把空的掛到librarycache上
然後執行下一個sql

因爲sql共享做的不好
帶來一個問題
剛纔複雜的花了很長時間
把這個sql掛到了寫到了librarycache上
因爲共享做的不好後面沒有被使用
後面每條sql語句都是硬解析
每條sql語句都重複着剛纔講的故事
找、去解析、找空的、掛過去

如果說反過來講
現在一條sql語句來了
不去librarycache裏面找
sql語句解析完了也不去緩存
sql語句來了直接硬解析
解析完了執行
執行完了把解析結果就扔了
這樣的話比剛纔的步驟還簡單

結論:
如果sql語句沒有共享
大量的硬解析時sharedpool的作用是反的

在這種情況下
如果我把sharedpool設的很大
在沒有實現共享sql的前提下
oracle的硬解析會非常的多
而硬解析的每一步都要執行
即使很多步驟對執行一條命令獲得結果並沒有作用
這個時候有sharedpool不如沒有sharedpool,它浪費了太多資源

當然oracle不可能沒有sharedpool我們只是這麼說

2、第二種壞處
如果我把sharedpool設的很大
librarycache裏面就會很大
sharedpool設的很大,大量的sql就會被緩存到librarycache裏面
也就是librarycache裏面的鏈會非常的長

鏈長的話一個sql語句來了
如果共享的話它應該掛在第一個鏈上
假設第一個鏈上有500個chunk
如果sharedpool小的話只能夠擱100個chunk
但是我們這裏放了500個chunk

這個sql語句就在這個鏈上一個一個比較到底一不一樣
因爲不一樣
所以這個sql語句要比較500個chunk
在比較這500個chunk的時候
因爲正在訪問這個鏈要把這個鏈鎖住

再回顧一下
因爲sharedpool設的很大,自然librarycache就大
自然librarycache上掛的chunk就多
這個時候一個sql語句在一個鏈上找一個chunk的時候
因爲它是硬解析它在這個鏈上肯定沒有
它就會把500個都比較完
就會長時間的鎖住這個鏈
它鎖住這個鏈
另外一個sql也同樣找鏈的時候
會發生鏈的爭用 鎖的爭用

總結:
shared_pool大了鏈就會很長
自己遍歷鏈花很長時間
而且和別的sql可能會發生鏈的爭用使其它sql等待很長時間
危害就更大

二)給shared pool選擇合適的大小值

1)給shared pool單獨選擇合適的大小值

所以說在oracle以前老的版本里面
在oracle10以前
sharedpool我們建議不要超過一個G
超過一個G可能會帶來反作用

從oracle10G開始
可以設置超過1G
如:2G、5G
老師看過一個生產系統上
一個sharedpool設了10G
可以設的大一些
因爲在oracle10G裏面
它用了這麼一個技術
它把一個大的sharedpool設成很多子的sharedpool
也就是設成了多個小的sharedpool
每個小的sharedpool裏
都有自己的一些鏈
它保證這些鏈不會太長
但是我們也不要設太大

手工設sharedpool時如何選擇大小
oralce有相關的語句可以執行

SELECT 'Shared Pool' component,shared_pool_size_for_estimate estd_sp_size,
estd_lc_time_saved_factor parse_time_factor,
CASE           
WHEN current_parse_time_elapsed_s + adjustment_s < 0 
THEN           0           
ELSE            
current_parse_time_elapsed_s + adjustment_s       
END response_time    
FROM (SELECT shared_pool_size_for_estimate,shared_pool_size_factor,
estd_lc_time_saved_factor,a.estd_lc_time_saved,
e.VALUE/100 current_parse_time_elapsed_s,
c.estd_lc_time_saved - a.estd_lc_time_saved adjustment_s FROM v$shared_pool_advice a,
(SELECT * FROM v$sysstat WHERE NAME = 'parse time elapsed') e,
(SELECT estd_lc_time_saved FROM v$shared_pool_advice WHERE shared_pool_size_factor = 1) c);

這個語句較長在實際複製粘貼或保存時
因爲使用的是記事本編輯可能在語句中多出很多看不見的回車換行符,
要自己實際調整去掉多餘的隱藏字符,纔可正常運行。
方法可在整句結束時換行或者在“,”後換行,這樣可正確解析這個語句。

因爲自己搭建的環境和老師使用的環境不同,所以結果也有所差別
自己的結果如下

COMPONENT   ESTD_SP_SIZE PARSE_TIME_FACTOR RESPONSE_TIME
----------- ------------ ----------------- -------------
Shared Pool           64             .9871          23.3
Shared Pool           76             .9943          18.3
Shared Pool           88             .9986          15.3
Shared Pool          100                 1          14.3
Shared Pool          112                 1          14.3
Shared Pool          124                 1          14.3
Shared Pool          136                 1          14.3
Shared Pool          148                 1          14.3
Shared Pool          160                 1          14.3
Shared Pool          172                 1          14.3
Shared Pool          184                 1          14.3
Shared Pool          196                 1          14.3
Shared Pool          208                 1          14.3

13 rows selected.

結果中
COMPONENT(組件)列爲shared Pool
ESTD_SP_SIZE列
爲假設shared Pool的大小值
RESPONSE_TIME列
爲sql語句反應時間
是預測到的一個sql語句解析花費的平均時間

shared pool設的值不同,預測花費的時間可能會有改變

結果中 shared pool爲64M  一個sql語句解析花費的時間爲23.3
                  爲76M  響應時間爲18.3
                  爲88M  響應時間爲15.3
                  爲100M 響應時間爲14.3
總體隨着預設的ESTD_SP_SIZE值的增加
相應的響應時間在減少
這是好事

但是ESTD_SP_SIZE增加到一定程度以後
上例爲
Shared Pool          100                 1          14.3
Shared Pool          112                 1          14.3
隨着空間的增加
RESPONSE_TIME的數值就不變了

這樣shared pool設到
RESPONSE_TIME值穩定後的第一個值就可以了
這裏是100M
在我的軟硬件環境設爲100M就可以了。

我的實驗系統使用的虛擬機沒有負載反應的不太真實
而且從實踐中可以看到
從數據庫剛啓動開始
隨着oracle數據庫運行時間的增加
預測得到的最佳sharedpool的大小值會一步步增加。
因爲隨着運行時間增長數據庫負載會增大
相同sharedpool大小造成的響應時間會變長,
而且最佳大小的值也在增大。
就是這個預測值是在變化的。

實際通過這個sql語句取出相關的值以後
一般的取
PARSE_TIME_FACTOR
的值從1開始(後面的值一般都是1)對應的ESTD_SP_SIZE數據
就是我們應該設的

這是sharedpool單獨設的方法

2)給sga選擇合適的大小值
如果沒有手工設sharedpool
sharedpool純粹的用sga_target自動設置
我們判斷sga_target到底多大就可以了

其實可以在em裏面查詢設置sga

首先啓動em
使用ie瀏覽器,我的本機網址
http://192.168.3.47:1158/em
以SYSDBA身份登錄
在首頁 相關鏈接 中找到
指導中心

在指導中心頁找到
指導 內存指導

進入 內存參數 頁
在SGA標籤頁
在 當前分配 中有
SGA總大小(MB) 
我的值是 272
點後面的建議按鈕,打開 SGA大小建議 圖表

當SGA的值超過一定點的時候 
SGA總大小(MB) 改變 數據庫時間的改善百分比 就不變了
對數據庫影響就不大了

SGA實際大小在這個圖表中調整也可以
如果空間足夠的話,可以設的稍微大一些

這個地方講的是我們如何去設置sharedpool的大小
有兩種預測選擇大小值的方法
一個是使用em一個直接使用sql語句查

在Oracle10g中允許有多個sub shared pool,可以設置大於1G的shared pool
oracle10G以前都小於1G
oracle10G以後都大於1G
儘量不要太大

三)執行計劃

sga的sharedpool裏面librarycache裏面緩存的是執行計劃
我們可以看一下執行計劃

可以使用查詢語句
select * from table(dbms_xplan.display_cursor('g4pkmrqrgxg3b'));
查到執行計劃
其中g4pkmrqrgxg3b是sqlID,不同的sql語句ID不同
把sqlID找出以後把它覆蓋就可以執行了

假設去執行一個語句並找到它的執行計劃

SQL> alter system flush shared_pool;

System altered.

先清了shared_pool,
這個語句的執行,是爲了使舉例語句每次運行的環境基本相同
這樣生成的執行計劃也基本是相同的
可能這個語句太簡單
比較老師機子生成的執行計劃
和我的機子生成的執行計劃只有個別地方有微小的區別。
執行計劃是爲了使語句執行過程最優化
它的生成要根據軟硬件環境由oracle去選擇最優的方案
所以有些oracle所在內外部環境的變化可以使生成的計劃發生變化
如要檢索的表是否使用索引會造成生成的執行計劃不同。

執行一下要查看它的執行計劃的語句
SQL> select count(*) from dba_objects;

  COUNT(*)
----------
     50361
執行了以後這個sql語句的執行計劃應該在librarycache裏面出現了

現在看看執行計劃是什麼
首先找sql語句對應的sqlID
SQL> select sql_id,sql_text from v$sql where sql_text like '%count(*) from dba_objects%';

SQL_ID
-------------
SQL_TEXT
----------------------------------------------------------------------------------------------------
g4pkmrqrgxg3b
select count(*) from dba_objects

發現對應的sqlID是g4pkmrqrgxg3b

然後使用
select * from table(dbms_xplan.display_cursor('g4pkmrqrgxg3b'));
查看執行計劃
這條語句的結果較長
可以將sql命令行輸出的行寬和頁長改大以使結果顯示的有條理
可以設置linesize、pagesize的大小
SQL> set linesize 100
設置顯示結果中每行的長度
SQL> set pagesize 1000
設置顯示結果每頁多少行
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
SQL> select * from table(dbms_xplan.display_cursor('g4pkmrqrgxg3b'));

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
SQL_ID  g4pkmrqrgxg3b, child number 0
-------------------------------------
select count(*) from dba_objects

Plan hash value: 2598313856

-----------------------------------------------------------------------------------------------
| Id  | Operation                       | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                |             |       |       |   144 (100)|          |
|   1 |  SORT AGGREGATE                 |             |     1 |       |            |          |
|   2 |   VIEW                          | DBA_OBJECTS | 48840 |       |   144   (5)| 00:00:02 |
|   3 |    UNION-ALL                    |             |       |       |            |          |
|*  4 |     FILTER                      |             |       |       |            |          |
|*  5 |      HASH JOIN                  |             | 51423 |  4117K|   143   (5)| 00:00:02 |
|   6 |       TABLE ACCESS FULL         | USER$       |    62 |   186 |     2   (0)| 00:00:01 |
|*  7 |       TABLE ACCESS FULL         | OBJ$        | 51423 |  3967K|   140   (4)| 00:00:02 |
|*  8 |      TABLE ACCESS BY INDEX ROWID| IND$        |     1 |     8 |     2   (0)| 00:00:01 |
|*  9 |       INDEX UNIQUE SCAN         | I_IND1      |     1 |       |     1   (0)| 00:00:01 |
|  10 |     NESTED LOOPS                |             |     1 |    16 |     1   (0)| 00:00:01 |
|  11 |      INDEX FULL SCAN            | I_LINK1     |     1 |    13 |     0   (0)|          |
|  12 |      TABLE ACCESS CLUSTER       | USER$       |     1 |     3 |     1   (0)| 00:00:01 |
|* 13 |       INDEX UNIQUE SCAN         | I_USER#     |     1 |       |     0   (0)|          |
-----------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - filter((("O"."TYPE#"<>1 AND "O"."TYPE#"<>10) OR ("O"."TYPE#"=1 AND =1)))
   5 - access("O"."OWNER#"="U"."USER#")
   7 - filter(("O"."NAME"<>'_NEXT_OBJECT' AND "O"."NAME"<>'_default_auditing_options_'
              AND "O"."LINKNAME" IS NULL))
   8 - filter(("I"."TYPE#"=1 OR "I"."TYPE#"=2 OR "I"."TYPE#"=3 OR "I"."TYPE#"=4 OR
              "I"."TYPE#"=6 OR "I"."TYPE#"=7 OR "I"."TYPE#"=9))
   9 - access("I"."OBJ#"=:B1)
  13 - access("L"."OWNER#"="U"."USER#")

37 rows selected.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
這樣的結果很清晰

可看出結果是關於sql語句
select count(*) from dba_objects
對應的一個執行計劃

只有讀懂執行計劃
你才能知道執行計劃好不好

到目前爲止,我們相對深入的講了oracle的sharedpool
裏面內容比較多也比較雜亂一些
沒有一個很好的思路去講這個東西
很多知識是中間插進來的
大家以後把視頻多看幾遍慢慢就掌握了

2016年8月27日
文字:韻箏

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章