Oracle 11g新特性之緩存與連接池

Oracle 11g新特性之緩存與連接池

上一篇 /下一篇  2008-03-26 16:03:19 / 個人分類:Oracle 數據庫 11g面向 DBA 和開發人員的重要新特性

緩存和連接池

探究如何使用 SQL 結果緩存、PL/SQL 功能緩存和客戶端緩存以及數據庫駐留連接池來改善性能。

SQL 結果緩存

訪問內存比訪問硬盤快得多,在接下來幾年中,除非硬盤體系結構有重大改進,不然這一情況很可能會持續。緩存這一將數據存儲於內存而非硬盤中的過程由此應運而生。緩存是Oracle 數據庫體系結構的一個基本原理,用戶從緩存而非數據庫所駐留的磁盤中獲取數據。

在相對較小的含靜態數據的表中,如 STATES、PRODUCT_CODES 等參考表,緩存的優勢異乎尋常的明顯。但是,假設有一個存儲公司客戶的大型表 CUSTOMERS。列表相對靜態但不完全是,在向列表中添加或從列表中刪除客戶時,表極少更改。

緩存在這一情況中也有些許用武之地。但如果您要緩存該表,如何在發生變化時確保獲得正確的數據?

Oracle 數據庫 11g可以解決這一問題:使用 QL 結果緩存。假設查詢如下。運行它以獲取執行統計信息和響應時間:

SQL> set autot on explain stat

select
  state_code,
  count(*),
  min(times_purchased),
  avg(times_purchased)
from customers
group by state_code
/

結果是:

ST   COUNT(*) MIN(TIMES_PURCHASED) AVG(TIMES_PURCHASED)
-- ---------- -------------------- --------------------
NJ          1                   15                   15
NY     994898                    0           15.0052086
CT       5099                    0           14.9466562
MO          1                   25                   25
FL          1                    3                    3
 
5 rows selected.
 
Elapsed: 00:00:02.57
 
Execution Plan
----------------------------------------------------------
Plan hash value: 1577413243
 
--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     5 |    30 |  1846  (25)| 00:00:23 |
|   1 |  HASH GROUP BY     |           |     5 |    30 |  1846  (25)| 00:00:23 |
|   2 |   TABLE ACCESS FULL| CUSTOMERS |  1000K|  5859K|  1495   (7)| 00:00:18 |
--------------------------------------------------------------------------------
 
 
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
       5136  consistent gets
       5128  physical reads
          0  redo size
        760  bytes sent via SQL*Net to client
        420  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          5  rows processed

幾點注意事項:

  • 解釋計劃說明執行了全表掃描。
  • 共有 5,136 次連續的獲取(邏輯 I/O)。
  • 執行時間 2.57 秒。

因爲表幾乎沒變,您可以使用提示來存儲要緩存到內存中的查詢結果:

select /*+ result_cache */
        state_code,
        count(*),
        min(times_purchased),
        avg(times_purchased)
from customers
group by state_code
/

除提示外,查詢與第一個相同。結果(第二次執行該查詢):

ST   COUNT(*) MIN(TIMES_PURCHASED) AVG(TIMES_PURCHASED)
-- ---------- -------------------- --------------------
NJ          1                   15                   15
NY     994898                    0           15.0052086
CT       5099                    0           14.9466562
MO          1                   25                   25
FL          1                    3                    3
 
5 rows selected.
 
Elapsed: 00:00:00.01
 
Execution Plan
----------------------------------------------------------
Plan hash value: 1577413243
 
--------------------------------------------------------------------------------------------------
| Id  | Operation           | Name                       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |                            |     5 |    30 |  1846  (25)| 00:00:23 |
|   1 |  RESULT CACHE       | gk69saf6h3ujx525twvvsnaytd |       |       |            |          |
|   2 |   HASH GROUP BY     |                            |     5 |    30 |  1846  (25)| 00:00:23 |
|   3 |    TABLE ACCESS FULL| CUSTOMERS                  |  1000K|  5859K|  1495   (7)| 00:00:18 |
--------------------------------------------------------------------------------------------------


Result Cache Information (identified by operation id):
------------------------------------------------------
 
   1 - column-count=4; dependencies=(ARUP.CUSTOMERS); parameters=(nls); name="select /*+ result_cache */
        state_code,
        count(*),
        min(times_purchased),
        avg(times_purchased)
from customers
group by state_c"
 
 
 
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          0  consistent gets
          0  physical reads
          0  redo size
        760  bytes sent via SQL*Net to client
        420  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          5  rows processed

注意與第一次的不同之處。

  • 響應時間現在爲 0.01 秒,而不是先前的將近 3 秒。
  • 連續的獲取爲 0,這一查詢沒有執行邏輯 I/O。(事實上,首次運行帶有提示的查詢時,I/O 將保持不變,因爲數據庫需要執行 I/O 來構建緩存。後續的調用將從緩存中供應數據,從而消除了 I/O。)
  • 這一解釋計劃將 RESULT CACHE 視爲一個操作。
  • 解釋計劃的注意事項指明執行的緩存類型以及緩存結果。

在時間上的節約是顯著的:從 3 秒到幾乎爲 0!這是因爲第二次查詢使用了緩存,結果直接來自數據庫內存(結果緩存)而不是執行查詢。

SQL 結果緩存是 SGA 中的另一個緩存,與緩衝區緩存或程序全局區一樣。當您執行帶有 result_cache 提示的查詢時,Oracle 執行該操作的過程與其他操作一樣,只是結果存儲在 SQL 結果緩存中。接下來對同一查詢的調用將不訪問表,而是從緩存中獲取結果。緩存大小由幾個初始化參數確定:

參數 說明
result_cache_max_size 結果緩存上限(例如,5M 上限)。如果將它設爲 0,將完全關閉結果緩存。
result_cache_max_result 指定任一結果可使用的 result_cache_max_size 百分比
result_cache_mode 如設置爲 FORCE,如果緩存可以容納所有查詢,就會緩存它們。默認值爲 MANUAL 表示只緩存帶有提示的查詢。
result_cache_remote_expiration 指定訪問遠程對象的緩存結果保持有效的時間(以分鐘爲單位)。默認爲 0。
現在,有一個邏輯問題:當錶行更改時,將發生什麼情況?查詢將獲取新值還是舊值?好,讓我們來看一看。從另一個 SQL*Plus 會話更新表中的某一行:
SQL> update customers set times_purchased = 4
  2  where state_code = 'FL';
 
1 row updated.

但是不要提交。在首次運行查詢的原窗口中,再運行一次。使用的是仍是緩存結果,因爲更改沒有提交。運行查詢的會話仍然查看最新版本的數據,緩存仍舊有效。

現在,從您進行更新操作的會話中,發出提交指令,然後運行查詢。

ST   COUNT(*) MIN(TIMES_PURCHASED) AVG(TIMES_PURCHASED)
-- ---------- -------------------- --------------------
NJ          1                   15                   15
NY     994898                    0           15.0052086
CT       5099                    0           14.9466562
MO          1                   25                   25
FL          1                    4                    4

注意 FL 的數據自動更新爲 4。底層表的更改致使緩存無效,因而在下一次查詢它時將動態更新。無論您是否使用 SQL 結果緩存,都能保證獲得正確的結果。

差異與物化視圖

熟悉物化視圖 (MV) 的人可能想這一功能與 MV 的功能有什麼區別。答案是:有很多區別。表面上他們很相似,都是用某種方法保存結果,從保存的數據集中提供答案,但他們的相似之處也僅限於此了。MV 將數據保存在數據庫存儲中,而 SQL 結果緩存位於內存中。它們不使用更多的磁盤空間,當數據庫實例關閉後,它們會消失,或者 result_cache 中的磁盤空間將耗盡。

MV 也是靜態的,當底層表中的數據更改時,MV 並不知道。除非您刷新 MV,否則在您將 query_rewrite_integrity 設爲 stale_tolerated 的情況下,用戶可能獲得的是舊數據,或者用戶需要針對底層表重新運行基本查詢,而這將花費更多的時間。使用 SQL 結果緩存,您不需要顯式刷新緩存;下一次運行查詢時,緩存將自動刷新。

MV 提供了一個更爲複雜的重寫算法。首次對結果進行緩存後,只有重新運行同一查詢或查詢片段時纔會重用緩存的結果(且底層數據未更改)。受益於對 MV 進行查詢重寫的查詢仍可從物化視圖上卷數據,聯結回表或其他物化視圖,並應用其他謂詞,這是數據倉庫環境中很重要的一個特點。

因此,MV 和 SQL 結果緩存是不可比或不可互換的,它們各具千秋。

子查詢

您也能在子查詢中使用 SQL 結果緩存。請看以下查詢:

select prod_subcategory, revenue
from (
   select /*+ result_cache */ p.prod_category,
      p.prod_subcategory,
      sum(s.amount_sold) revenue
   from products p, sales s
   where s.prod_id = p.prod_id 
   and s.time_id between to_date('01-jan-1990','dd-mon-yyyy')
   and to_date('31-dec-2007','dd-mon-yyyy')
   group by rollup(p.prod_category, p.prod_subcategory)
)
where prod_category = 'software/other'
/

在上面的查詢中,緩存發生在內聯視圖的子查詢中。因此,只要內聯查詢保持不變,外部查詢就可以更改且可使用緩存。

要檢查有多少內存用於數據庫中的 SQL 結果緩存,您可以使用提供的程序包 dbms_result_cache,如下所示:

SQL> set serveroutput on size 999999
SQL> execute dbms_result_cache.memory_report
R e s u l t   C a c h e   M e m o r y   R e p o r t
[Parameters]
Block Size          = 1K bytes
Maximum Cache Size  = 2560K bytes (2560 blocks)
Maximum Result Size = 128K bytes (128 blocks)
[Memory]
Total Memory = 126736 bytes [0.041% of the Shared Pool]
... Fixed Memory = 5132 bytes [0.002% of the Shared Pool]
... Dynamic Memory = 121604 bytes [0.040% of the Shared Pool]
....... verhead = 88836 bytes
....... Cache Memory = 32K bytes (32 blocks)
........... Unused Memory = 21 blocks
........... Used Memory = 11 blocks
............... Dependencies = 4 blocks (4 count)
............... Results = 7 blocks
................... SQL     = 5 blocks (4 count)
................... Invalid = 2 blocks (2 count)
 
PL/SQL procedure successfully completed.

如果您因故想清空緩存(包括結果緩存和功能緩存,如下描述),可以使用:

begin 
   dbms_result_cache.flush;
end;

執行以上命令後,通過 result_cache 提示對 CUSTOMERS 運行原始查詢後,您將再次看到查詢需要 3 秒完成。

當然,第一次運行後,結果將再次緩存,後續執行將從結果緩存中獲取值,因此執行速度將更快。如果您只想使一個表的緩存無效,而不是整個緩存,可以使用以下命令:

begin
  dbms_result_cache.invalidate('ARUP','CUSTOMERS');
end;

有幾個數據詞典視圖列出了 SQL 結果緩存的統計數據:

視圖 說明
V$RESULT_CACHE_STATISTICS 顯示不同的設置,特別是內存使用
V$RESULT_CACHE_MEMORY 顯示組成 SQL 結果緩存的各內存塊
V$RESULT_CACHE_OBJECTS 顯示組成 SQL 結果緩存的對象
V$RESULT_CACHE_DEPENDENCY 顯示組成 SQL 結果緩存的各個對象間的依賴關係

SQL 結果緩存使您能夠緩存訪問大量數據的查詢的結果。當底層表更改時,如果您沒有干預或另外編寫代碼,緩存將自動失效。

PL/SQL 功能結果緩存

假設您使用一個 PL/SQL 函數(而不是 SQL 查詢)來返回值。這種使用函數返回值來構造代碼模塊的做法很常見。假設有兩個表:CUSTOMERS 存儲所有客戶的信息以及 state_code。另一個表 TAX_RATE 存儲每個州的稅率。要獲得適用於客戶的稅率,您需要在查詢中聯結表。因此,爲簡化這一過程,您打算編寫如下函數,以接受客戶 ID 作爲參數,並基於 state_code 返回相應的稅率:

create or replace function get_tax_rate
(
        p_cust_id       customers.cust_id%type
)
return sales_tax_rate.tax_rate%type
is
        l_ret   sales_tax_rate.tax_rate%type;
begin
        select tax_rate
        into l_ret
        from sales_tax_rate t, customers c
        where c.cust_id = p_cust_id
        and t.state_code = c.state_code;
        -- simulate some time consuming
        -- processing by sleeping for 1 sec
        dbms_lock.sleep (1);
        return l_ret;
exception
        when NO_DATA_FOUND then
                return NULL;
        when others then
                raise;
end;
/

執行幾次函數,如下所示。記住要啓用計時來記錄每次執行使用的時間。

SQL> select get_tax_rate(1) from dual;
 
GET_TAX_RATE(1)
---------------
              6
 
1 row selected.
 
Elapsed: 00:00:01.23
SQL> select get_tax_rate(1) from dual;
 
GET_TAX_RATE(1)
---------------
              6
 
1 row selected.
 
Elapsed: 00:00:01.17

每次執行使用的時間幾乎都相同。(我特意使用了休眠語句來延遲函數內的處理;否則返回速度太快。)如果您仔細分析代碼,將注意到每次調用函數時,幾乎都會返回相同的值。客戶不經常更改所在的州,並且州的稅率也很少變化,因此對於同一個客戶,每次執行的稅率幾乎完全相同。當且僅當州稅率更改或客戶搬離該州時,稅率纔會變化。因此,緩存這一函數的結果會怎麼樣呢?

Oracle 數據庫 11g可讓您完成這一任務。您也可以使用 result_cache 子句實現對函數結果的緩存。但當州實際上更改了稅率或客戶搬離州時,又該如何呢?這一特性讓您可以指定對底層表的依賴,因此那些表中的數據更改將觸發失效操作,並隨後重建函數中的緩存。以下是添加了結果緩存代碼的同一函數(粗體):

create or replace function get_tax_rate
(
        p_cust_id       customers.cust_id%type
)
return sales_tax_rate.tax_rate%typeresult_cache
relies_on (sales_tax_rate, customers)is
        l_ret   sales_tax_rate.tax_rate%type;
begin
        select tax_rate
        into l_ret
        from sales_tax_rate t, customers c
        where c.cust_id = p_cust_id
        and t.state_code = c.state_code;
        -- simulate some time consuming
        -- processing by sleeping for 1 sec
        dbms_lock.sleep (1);
        return l_ret;
exception
        when NO_DATA_FOUND then
                return NULL;
        when others then
                raise;
end;
/

更改後,以同一方式創建和執行函數:

SQL> select get_tax_rate(1) from dual;
 
GET_TAX_RATE(1)
---------------
              6
 
1 row selected.
 
Elapsed: 00:00:01.21

需要 1.21 秒,與上次使用非緩存方式一樣,但我們來看一下隨後的執行:

SQL> select get_tax_rate(1) from dual;
 
GET_TAX_RATE(1)
---------------
              6
 
1 row selected.
 
Elapsed: 00:00:00.01

使用的時間只有 0.01 秒!到底是怎麼回事?函數執行第一次時,耗時 1.21 秒。但這一次的重要區別是它在執行時緩存了結果。後續的調用不執行該函數,只從緩存中獲取結果。因此,它沒有休眠函數代碼中指定的 1 秒鐘。

緩存只針對 customer_id 1。如果針對另一個客戶執行函數,又會如何?

SQL> select get_tax_rate(&n) from dual;
Enter value for n: 5
old   1: select get_tax_rate(&n) from dual
new   1: select get_tax_rate(5) from dual
 
GET_TAX_RATE(5)
---------------
              6
 
1 row selected.
 
Elapsed: 00:00:01.18
SQL> /
Enter value for n: 5
old   1: select get_tax_rate(&n) from dual
new   1: select get_tax_rate(5) from dual
 
GET_TAX_RATE(5)
---------------
              6
 
1 row selected.
 
Elapsed: 00:00:00.00
SQL> /
Enter value for n: 6
old   1: select get_tax_rate(&n) from dual
new   1: select get_tax_rate(6) from dual
 
GET_TAX_RATE(6)
---------------
              6
 
1 row selected.
 
Elapsed: 00:00:01.17

您可以看到,首次執行每個參數時,它會緩存結果。後續的調用從緩存中檢索值。隨着您針對各個客戶執行該函數,緩存會逐漸增大。

注意函數代碼中的“relies on”子句。它將告知函數緩存依賴哪兩個表:customers 和 tax_rate。如果那些表中的數據更改,那麼緩存就需要刷新。刷新會自動發生,不需要您干預。如果數據未更改,緩存將繼續儘可能快地提供緩存的值。

如果因故要繞過緩存,您可以調用提供的程序包 DBMS_RESULT_CACHE 中的過程:

SQL> exec dbms_result_cache.bypass(true);
 
PL/SQL procedure successfully completed.
 
Elapsed: 00:00:00.01

SQL> select get_tax_rate(&n) from dual;
Enter value for n: 6
old   1: select get_tax_rate(&n) from dual
new   1: select get_tax_rate(6) from dual
 
GET_TAX_RATE(6)
---------------
              6
 
1 row selected.
 
Elapsed: 00:00:01.18

從執行時間上可以看出,沒有使用緩存。

緩存與程序包變量

對 SQL 結果緩存和 PL/SQL 函數緩存,您也可以使用程序包變量(可以是標量數據類型或 PL/SQL 集合)實現在內存中緩存值。應用程序可以訪問變量,而不是錶行或函數。因爲基於內存,它的行爲像緩存,那麼 SQL 結果緩存添加了什麼值?

差別衆多。對一個客戶(假設 cust_id = 5)執行該函數後,從另一個會話對同一客戶執行該函數:

SQL> select get_tax_rate(&n) from dual
  2  /
Enter value for n: 5
old   1: select get_tax_rate(&n) from dual
new   1: select get_tax_rate(5) from dual
 
GET_TAX_RATE(5)
---------------
              6
 
1 row selected.
 
Elapsed: 00:00:00.00

注意執行時間,它表明結果源自緩存,而不是通過函數的執行。因此,儘管會話中沒有緩存該函數,任一調用它的會話仍然可以從緩存中使用它。

緩存針對數據庫實例,而不是會話。這一讓所有其他會話能使用一個會話中的緩存的能力極其不同於使用程序包變量在內存中保存值的方法,在這一方法中,變量只能在一個會話中可見。

而且,程序包變量無法感知底層表的更改。當數據更改時,您需要手動刷新數據,否則應用程序將獲取陳舊數據。在底層表數據更改時,SQL 結果緩存和 PL/SQL 函數緩存會自動刷新緩存,不需用戶介入。

客戶端查詢結果緩存

假設有這樣一個情形:客戶端需要通過慢速網絡鏈接調用同一數據。儘管數據庫可以立即將結果從緩存發送到客戶端,但結果必須通過線路傳送到客戶端,這就增加了整體執行時間。現在有一些專門的中間件框架(如 Oracle Coherence),用於在Java、PHP 和 Ruby 中緩存數據,如果有一個在客戶端級別緩存數據的通用方法,又將如何呢?

爲此,Oracle 數據庫 11g提供了“客戶端查詢結果緩存”。所有使用 OCI8 驅動程序的數據庫客戶端堆棧(C、C++、JDBC-OCI 等)都可以使用這一新特性,使客戶端能夠在本地緩存 SQL 查詢的結果,而不是在服務器上。總言之,客戶端查詢結果緩存可以提供以下好處:

  • 使應用程序開發人員不用構建由所有會話共享的一致的每一流程的 SQL 結果緩存
  • 通過利用更便宜的客戶端內存並在本地緩存每個應用程序的工作集,將服務器端查詢緩存擴展到客戶端內存,
  • 從而消除到服務器的往返過程,確保更好的性能
  • 通過節約服務器資源,改善服務器可伸縮性
  • 提供透明的緩存管理:內存管理、結果集的併發訪問等
  • 透明地維護緩存與服務器端更改的一致性
  • RAC 環境中提供一致性

要使用這一特性,您所要做的就是設置一個初始化參數:

CLIENT_RESULT_CACHE_SIZE = 1G

該參數定義客戶端緩存爲 1GB,這是所有客戶端的總緩存大小。(這是一個靜態參數,因此您必須重啓數據庫來設置它。)您可以在每個客戶端中設置緩存,在客戶端位置的 SQLNET.ORA 文件中指定其他參數:

參數 說明
OCI_RESULT_CACHE_MAX_SIZE 指定該特定客戶端的緩存大小
OCI_RESULT_CACHE_MAX_RSET_SIZE 指定結果集大小的上限
OCI_RESULT_CACHE_MAX_RSET_ROWS 同上,但指定結果集行數的上限

讓我們看一看它的使用方式。這是簡單的 Java 代碼,它使用 OCI8 驅動程序連接到數據庫,然後執行 SQL 語句:select /*+ result_cache */ * from customers。提示致使語句緩存該結果(其他參數已經設置好)。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class CacheTest {
  private String jdbcURL = "jdbc:oracle:oci8:@PRONE3";
  private Connection conn = null;
  public CacheTest( ) throws ClassNotFoundException  {
    Class.forName("oracle.jdbc.driver.OracleDriver");
  }  
  public static void main(String[] args)  throws ClassNotFoundException, SQLException {
    CacheTest check = new CacheTest();
    check.dbconnect();
    check.doSomething();
  }
  public void dbconnect() throws SQLException   {
    System.out.println("Connecting with URL="+jdbcURL+" as arup/arup");
    try {
      conn = DriverManager.getConnection( jdbcURL, "arup" , "arup");
      System.out.println("Connected to Database");
    } catch (SQLException sqlEx) {
      System.out.println(" Error connecting to database : " + sqlEx.toString());
    }
  }
  public void doSomething() throws SQLException   {
    Statement stmt = null;
    ResultSet rset = null;
    try {
      stmt = conn.createStatement();
      System.out.println("Created Statement object");
      rset = stmt.executeQuery("select /*+ result_cache */ * from customers");
      System.out.println("Retrieved ResultSet object");
      if(rset.next())
        System.out.println("Result:"+rset.getString(1));
    } catch (SQLException sqlEx)     {
    } finally  {
      try {
        System.out.println("Closing Statment & ResultSet Objects");
        if (rset != null) rset.close();
        if (stmt != null) stmt.close();
        if (conn != null) {
          System.out.println("Disconnecting...");
          conn.close();
          System.out.println("Disconnected from Database");
        }
      } catch (Exception e) { }
    }
  }
}

將文件保存爲 CacheTest.java,然後編譯代碼:

$ORACLE_HOME/jdk/bin/javac CacheTest.java

現在,執行編譯後的類:

$ORACLE_HOME/jdk/bin/java -classpath .:$ORACLE_HOME/jdbc/lib/ojdbc5.jar CacheTest
Connecting with URL=jdbc:oracle:oci8:@PRONE3 as arup/arup
Connected to Database
Created Statement object
Retrieved ResultSet object
Result :M
Closing Statment & ResultSet Objects
Disconnecting...
Disconnected from Database

多執行幾次。幾次執行之後,您可以發現客戶端已通過動態視圖對值進行了緩存,如下所示:

select * from client_result_cache_stats$
/
select * from v$client_result_cache_stats
/

客戶端查詢結果緩存在查找很少改變的表時十分有用。(即使它們更改,也會刷新緩存。)這與 SQL 結果緩存不同,其緩存位於服務器上。由於客戶端緩存了結果,因此不需要在客戶端與服務器間往返以獲取數據 — 這不但節省了網絡帶寬,還節省了服務器 CPU 週期。有關更多信息,請參閱Oracle 調用接口編程人員指南

數據庫駐留連接池

在傳統的客戶端/服務器體系結構中,用戶會話和數據庫連接之間是一對一的通信。但在基於 Web 的系統中,情況可能有所不同。

基於 Web 的系統在本質上是“無狀態”的 — 當您訪問頁面時,將建立與數據庫的連接,頁面下載完成後,將切斷與數據庫的連接。稍後,當用戶再次單擊頁面時,將建立一個新的連接,目的達到後又將切斷連接。這一過程使得沒有必要維護大量的同步連接。

建立連接的開銷很大,因此連接池是這些應用程序的一個重要要求。在這一模式中,當頁面需要數據庫訪問時,會從池中分配一個已經建立的連接。完成工作後,Web 會話會將連接返回池中。

但傳統的客戶端或中間層連接池的問題是:

  • 每個池只限於單箇中間層節點。
  • 池的大量增長將導致預先分配的數據庫服務器過多和數據庫服務器內存使用過多。
  • 池中的工作負載分配不均。

爲避免這些問題,Oracle 數據庫 11g提供了一個服務器端池,稱爲數據庫駐留連接池 (DRCP)。DRCP 可用於使用 OCI 驅動程序的所有數據庫客戶端,包括 C、C++ 和 PHP。

Oracle 數據庫 11g預先安裝有默認的連接池,但是處於關閉狀態。要啓用它,使用:

execute dbms_connection_pool.start_pool;

現在,要連接到池中的連接而不是常規會話,您要做的就是在 TNS 條目中添加一行 (SERVER=POOLED),如下所示:

PRONE3_POOL =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = prolin3.proligence.com)(PORT = 1521))
    (CONNECT_DATA =(SERVER = POOLED)(SID = PRONE3)
    )
  )

現在,更改代碼中的connect字符串,在這一代碼中它連接到數據庫。使用上面“客戶端結果緩存”部分中的示例代碼:

private String jdbcURL = "jdbc:oracle:oci8:@PRONE3_POOL";

就這樣了。現在,您的應用程序將連接到池而不是服務器。如果您使用瘦客戶端且使用標準的 JDBC 連接字符串,則可以使用 POOLED 子句:

prolin3. proligence.com:1521/PRONE3:POOLED

在上面的描述中,您啓用了 Oracle 附帶的默認池,選項爲默認的。您可以使用提供的 DBMS_CONNECTION_POOL 程序包中的 CONFIGURE_POOL 過程:

參數

說明

POOL_NAME

池的名稱。使用 ‘’(兩個單引號用於默認池)

MINSIZE

池中保存會話數量的下限

MAXSIZE

池中會話數量的上限

INCRSIZE

當池中的服務器不可用時,池將創建這一數量的新服務器

SESSION_CACHED_CURSORS

啓用會話緩存遊標

INACTIVITY_TIMEOUT

如果會話閒置時間達到這一時長,將斷開。

MAX_THINK_TIME

當客戶端從池中獲取一個服務器後,它必須在這一時間段內發出 SQL 語句,否則客戶端將丟失服務器

MAX_USE_SESSION

從池中取還一個連接的最多次數

MAX_LIFETIME_SESSION

會話的持續時間


DRCP 功能非常重要,因爲單個池可在一個普通平臺上維持數萬同步用戶。此外,單個池可以在多個客戶端和中間層節點間共享,並且在 RAC 和 Data Guard 環境中,DRCP 和 FAN 事件共同提供了快速的連接故障轉移。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章