Oracle 效能調優 概述

lygle發表於2013-03-26

在過去的十年中, Oracle 已經成為世界上最專業的資料庫之一。對於 IT 專家來說,就是要確保利用 Oracle 的強大特性來提高他們公司的生產力。最有效的方法之一是通過 Oracle 調優。它有大量的調整引數和技術來改進你的 Oracle 資料庫的效能。


Oracle 調優是一個複雜的主題。關於調優可以寫整整一本書,不過,為了改善 Oracle 資料庫的效能,有一些基本的概念是每個 Oracle DBA 都應該遵從的。

在這篇簡介中,我們將簡要地介紹以下的 Oracle 主題:
1) 外部調整:我們應該記住 Oracle 並不是單獨執行的。因此我們將檢視一下通過調整 Oracle 伺服器以得到高的效能2) Row re-sequencing 以減少磁碟 I/O :我們應該懂得 Oracle 調優最重要的目標是減少 I/O
3) Oracle SQL 調整: Oracle SQL 調整是 Oracle 調整中最重要的領域之一,只要通過一些簡單的 SQL 調優規則就可以大幅度地提升 SQL 語句的效能,這是一點都不奇怪的。

4) 調整 Oracle 排序:排序對於 Oracle 效能也是有很大影響的。

5) 調整 Oracle 的競爭:表和索引的引數設定對於 UPDATE INSERT 的效能有很大的影響。

一. 外部的效能問題
我們首先從調整 Oracle 外部的環境開始。如果記憶體和 CPU 的資源不足的話,任何的 Oracle 調整都是沒有幫助的。Oracle 並不是單獨執行的。 Oracle 資料庫的效能和外部的環境有很大的關係。

這些外部的條件包括有:
  CPU CPU 資源的不足令查詢變慢。當查詢超過了 Oracle 伺服器的 CPU 效能時,你的資料庫效能就受到 CPU 的限制。
  記憶體 可用於 Oralce 的記憶體數量也會影響 SQL 的效能,特別是在資料緩衝和記憶體排序方面。
  網路 大量的 Net 通訊令 SQL 的效能變慢。
  許多新手都錯誤的認為應該首先調整 Oracle 資料庫,而不是先確認外部資源是否足夠。實際上,如果外部環境出現瓶頸,再多的 Oracle 調整都是沒有幫助的。

  在檢查 Oracle 的外部環境時,有兩個方面是需要注意的:
  1 、當執行佇列的數目超過伺服器的 CPU 數量時,伺服器的效能就會受到 CPU 的限制。補救的方法是為伺服器增加額外的 CPU 或者關閉需要很多處理資源的元件,例如 Oracle Parallel Query
  2 、記憶體分頁。當記憶體分頁時,記憶體容量已經不足,而記憶體頁是與磁碟上的交換區進行互動的。補救的方法是增加更多的記憶體,減少 Oracle SGA 的大小,或者關閉 Oracle 的多執行緒伺服器。

  可以使用各種標準的伺服器工具來得到伺服器的統計資料,例如 vmstat,glance,top sar DBA 的目標是確保資料庫伺服器擁有足夠的 CPU 和記憶體資源來處理 Oracle 的請求。

. row-resequencing (行的重新排序)
  就象我們上面提到的,有經驗的 Oracle DBA 都知道 I/O 是響應時間的最大組成部分。其中磁碟 I/O 特別厲害,因為當 Oracle 由磁碟上的一個資料檔案得到一個資料塊時,讀的程式就必須等待物理 I/O 操作完成。磁碟操作要比資料緩衝慢 10,000 倍。因此,如果可以令 I/O 最小化,或者減少由於磁碟上的檔案競爭而帶來的瓶頸,就可以大大地改善 Oracle 資料庫的效能。

如果系統響應很慢,通過減少磁碟 I/O 就可以有一個很快的改善。如果在一個事務中通過按一定的範圍搜尋 primary-key 索引來訪問表,那麼重新以 CTAS 的方法組織表將是你減少 I/O 的首要策略。通過在物理上將行排序為和 primary-key 索引一樣的順序,就可以加快獲得資料的速度。

就象磁碟的負載平衡一樣,行的重新排序也是很簡單的,而且也很快。通過與其它的 DBA 管理技巧一起使用,就可以在高 I/O 的系統中大大地減少響應的時間。

在高容量的線上事務處理環境中( online transaction processing OLTP ),資料是由一個 primary 索引得到的,重新排序表格的行就可以令連續塊的順序和它們的 primary 索引一樣,這樣就可以在索引驅動的表格查詢中,減少物理 I/O 並且改善響應時間。這個技巧僅在應用選擇多行的時候有用,或者在使用索引範圍搜尋和應用發出多個查詢來得到連續的 key 時有效。對於隨機的唯一 primary-key (主鍵)的訪問將不會由行重新排序中得到好處。

讓我們看一下它是如何工作的。考慮以下的一個 SQL 的查詢,它使用一個索引來得到 100 行:
select salary from employee where last_name like 'B%';
這個查詢將會使用 last_name_index ,搜尋其中的每一行來得到目標行。這個查詢將會至少使用 100 次物理磁碟的讀取,因為 employee 的行存放在不同的資料塊中。不過,如果表中的行已經重新排序為和 last_name_index 的一樣,同樣的查詢又會怎樣處理呢?我們可以看到這個查詢只需要三次的磁碟 I/O 就讀完全部 100 個員工的資料(一次用作索引的讀取,兩次用作資料塊的讀取),減少了 97 次的塊讀取。

重新排序帶來的效能改善的程度在於在你開始的時候行的亂序性如何,以及你需要由序列中訪問多少行。至於一個表中的行與索引的排序鍵的匹配程度,可以檢視資料字典中的 dba_indexes dba_tables 檢視得到。

dba_indexes 的檢視中,檢視 clustering_factor 列。如果 clustering_factor 的值和表中的塊數目大致一樣,那麼你的表和索引的順序是一樣的。不過,如果 clustering_factor 的值接近表中的行數目,那就表明表格中的行和索引的順序是不一樣的。

行重新排序的作用是不可以小看的。在需要進行大範圍的索引搜尋的大表中,行重新排序可以令查詢的效能提高三倍。一旦你已經決定重新排序表中的行,你可以使用以下的工具之一來重新組織表格。
   使用 Oracle Create Table As Select (CTAS) 語法來拷貝表格
   Oracle9i 自帶的表格重新組織工具

. SQL 調優
  Oracle SQL 調優是一個複雜的主題,甚至是需要整本書來介紹 Oracle SQL 調優的細微差別。不過有一些基本的規則是每個 Oracle DBA 都需要跟從的,這些規則可以改善他們系統的效能。

SQL 調優的目標是簡單的:
  1) 消除不必要的大表全表搜尋:不必要的全表搜尋導致大量不必要的 I/O ,從而拖慢整個資料庫的效能。調優專家首先會根據查詢返回的行數目來評價 SQL 在一個有序的表中,如果查詢返回少於 40% 的行,或者在一個無序的表中,返回少於 7% 的行,那麼這個查詢都可以調整為使用一個索引來代替全表搜尋。對於不必要的全表搜尋來說,最常見的調優方法是增加索引。可以在表中加入標準的 B 樹索引,也可以加入 bitmap 和基於函式的索引。要決定是否消除一個全表搜尋,你可以仔細檢查索引搜尋的 I/O 開銷和全表搜尋的開銷,它們的開銷和資料塊的讀取和可能的並行執行有關,並將兩者作對比。在一些情況下,一些不必要的全表搜尋的消除可以通過強制使用一個 index 來達到,只需要在 SQL 語句中加入一個索引的提示就可以了。
在全表搜尋是一個最快的訪問方法時,將小表的全表搜尋放到快取中,調優專家應該確保有一個專門的資料緩衝用作行緩衝。在 Oracle7 中,你可以使用 alter table xxx cache 語句,在 Oracle8 或以上,小表可以被強制為放到 KEEP 池中緩衝。
  
2) 確保最優的索引使用 :對於改善查詢的速度,這是特別重要的。有時 Oracle 可以選擇多個索引來進行查詢,調優專家必須檢查每個索引並且確保 Oracle 使用正確的索引。它還包括 bitmap 和基於函式的索引的使用。

  3) 確保最優的 JOIN 操作:有些查詢使用 NESTED LOOP join 快一些,有些則是 HASH join 快一些,另外一些則是 sort-merge join 更快。

  這些規則看來簡單,不過它們佔 SQL 調優任務的 90% ,並且它們也無需完全懂得 Oracle SQL 的內部運作。

四. 調整 Oracle 排序
  排序是 SQL 語法中一個小的方面,但很重要,在 Oracle 的調整中,它常常被忽略。當使用 create index ORDER BY 或者 GROUP BY 的語句時, Oracle 資料庫將會自動執行排序的操作。通常,在以下的情況下 Oracle 會進行排序的操作:
  使用 Order by SQL 語句
  使用 Group by SQL 語句


  在建立索引的時候
  進行 table join 時,由於現有索引的不足而導致 SQL 優化器呼叫 MERGE SORT
  當與 Oracle 建立起一個 session 時,在記憶體中就會為該 session 分配一個私有的排序區域。如果該連線是一個專用的連線 (dedicated connection) ,那麼就會根據 init.ora sort_area_size 引數的大小在記憶體中分配一個 Program Global Area (PGA) 。如果連線是通過多執行緒伺服器建立的,那麼排序的空間就在 large_pool 中分配。不幸的是,對於所有的 session ,用做排序的記憶體量都必須是一樣的,我們不能為需要更大排序的操作分配額外的排序區域。因此,設計者必須作出一個平衡,在分配足夠的排序區域以避免發生大的排序任務時出現磁碟排序( disk sorts )的同時,對於那些並不需要進行很大排序的任務,就會出現一些浪費。當然,當排序的空間需求超出了 sort_area_size 的大小時,這時將會在 TEMP 表空間中分頁進行磁碟排序。磁碟排序要比記憶體排序大概慢 14,000 倍。

  上面我們已經提到,私有排序區域的大小是有 init.ora 中的 sort_area_size 引數決定的。每個排序所佔用的大小由 init.ora 中的 sort_area_retained_size 引數決定。當排序不能在分配的空間中完成時,就會使用磁碟排序的方式,即在 Oracle 例項中的臨時表空間中進行。

  磁碟排序的開銷是很大的,有幾個方面的原因。首先,和記憶體排序相比較,它們特別慢;而且磁碟排序會消耗臨時表空間中的資源。 Oracle 還必須分配緩衝池塊來保持臨時表空間中的塊。無論什麼時候,記憶體排序都比磁碟排序好,磁碟排序將會令任務變慢,並且會影響 Oracle 例項的當前任務的執行。還有,過多的磁碟排序將會令 free buffer waits 的值變高,從而令其它任務的資料塊由緩衝中移走。


. 調整 Oracle 的競爭
  Oracle 的其中一個優點時它可以管理每個表空間中的自由空間。 Oracle 負責處理表和索引的空間管理,這樣就可以讓我們無需懂得 Oracle 的表和索引的內部運作。不過,對於有經驗的 Oracle 調優專家來說,他需要懂得 Oracle 是如何管理表的 extent 和空閒的資料塊。對於調整擁有高的 insert 或者 update 的系統來說,這是非常重要的。

  要精通物件的調整,你需要懂得 freelists freelist 組的行為,它們和 pctfree pctused 引數的值有關。這些知識對於企業資源計劃( ERP )的應用是特別重要的,因為在這些應用中,不正確的表設定通常是 DML 語句執行慢的原因。
  對於初學者來說,最常見的錯誤是認為預設的 Oracle 引數對於所有的物件都是最佳的。除非磁碟的消耗不是一個問題,否則在設定表的 pctfree pctused 引數時,就必須考慮平均的行長和資料庫的塊大小,這樣空的塊才會被有效地放到 freelists 中。當這些設定不正確時,那些得到的 freelists 也是 "dead" 塊,因為它們沒有足夠的空間來儲存一行,這樣將會導致明顯的處理延遲。

Freelists 對於有效地重新使用 Oracle 表空間中的空間是很重要的,它和 pctfree pctused 這兩個儲存引數的設定直接相關。通過將 pctused 設定為一個高的值,這時資料庫就會盡快地重新使用塊。不過,高效能和有效地重新使用表的塊是對立的。在調整 Oracle 的表格和索引時,需要認真考慮究竟需要高效能還是有效的空間重用,並且據此來設定表的引數。以下我們來看一下這些 freelists 是如何影響 Oracle 的效能的。

  當有一個請求需要插入一行到表格中時, Oracle 就會到 freelist 中尋找一個有足夠的空間來容納一行的塊。你也許知道, freelist 串是放在表格或者索引的第一個塊中,這個塊也被稱為段頭( segment header )。 pctfree pctused 引數的唯一目的就是為了控制塊如何在 freelists 中進出。雖然 freelist link unlink 是簡單的 Oracle 功能,不過設定 freelist link (pctused) unlink (pctfree) Oracle 的效能確實有影響。

  由 DBA 的基本知識知道, pctfree 引數是控制 freelist un-links 的(即將塊由 freelists 中移除)。設定 pctfree=10 意味著每個塊都保留 10% 的空間用作行擴充套件。 pctused 引數是控制 freelist re-links 的。設定 pctused=40 意味著只有在塊的使用低於 40% 時才會回到表格的 freelists 中。

  許多新手對於一個塊重新回到 freelists 後的處理都有些誤解。其實,一旦由於一個刪除的操作而令塊被重新加入到 freelist 中,它將會一直保留在 freelist 中即使空間的使用超過了 60% ,只有在到達 pctfree 時才會將資料塊由 freelist 中移走。

表格和索引儲存引數設定的要求總結
  以下的一些規則是用來設定 freelists, freelist groups, pctfree pctused 儲存引數的。你也知道, pctused pctfree 的值是可以很容易地通過 alter table 命令修改的,一個好的 DBA 應該知道如何設定這些引數的最佳值。

  有效地使用空間和高效能之間是有矛盾的,而表格的儲存引數就是控制這個方面的矛盾:
對於需要有效地重新使用空間,可以設定一個高的 pctused 值,不過副作用是需要額外的 I/O 。一個高的 pctused 值意味著相對滿的塊都會放到 freelist 中。因此,這些塊在再次滿之前只可以接受幾行記錄,從而導致更多的 I/O

追求高效能的話,可以將 pctused 設定為一個低的值,這意味著 Oracle 不會將資料塊放到 freelists 中直到它幾乎是空的。那麼塊將可以在滿之前接收更多的行,因此可以減少插入操作的 I/O 。要記住 Oracle 擴充套件新塊的效能要比重新使用現有的塊高。對於 Oracle 來說,擴充套件一個表比管理 freelists 消耗更少的資源。

讓我們來回顧一下設定物件儲存引數的一些常見規則:
  經常將 pctused 設定為可以接收一條新行。對於不能接受一行的 free blocks 對於我們來說是沒有用的。如果這樣做,將會令 Oracle 的效能變慢,因為 Oracle 將在擴充套件表來得到一個空的塊之前,企圖讀取 5 "dead" free block

  表格中 chained rows 的出現意味著 pctfree 太低或者是 db_block_size 太少。在很多情況下, RAW LONG RAW 列都很巨大,以至超過了 Oracle 的最大塊的大小,這時 chained rows 是不可以避免的。

  如果一個表有同時插入的 SQL 語句,那麼它需要有同時刪除的語句。執行單一個一個清除的工作將會把全部的空閒塊放到一個 freelist 中,而沒有其它包含有任何空閒塊的 freelists 出現。

  freelist 引數應該設定為表格同時更新的最大值。例如,如果在任何時候,某個表最多有 20 個使用者執行插入的操作,那麼該表的引數應該設定為 freelists=20

 應記住的是 freelist groups 引數的值只是對於 Oracle Parallel Server Real Application Clusters 才是有用的。對於這類 Oracle freelist groups 應該設定為訪問該表格的 Oracle Parallel Server 例項的數目。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28673746/viewspace-757136/,如需轉載,請註明出處,否則將追究法律責任。

相關文章