Oracle 11g新特性之快取與連線池

idba發表於2008-03-26

快取和連線池

探究如何使用 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%type
result_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 事件共同提供了快速的連線故障轉移。

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

相關文章