1. 程式人生 > >Oracle記憶體詳解之三 Shared pool 共享池

Oracle記憶體詳解之三 Shared pool 共享池

一. Shared Pool 概述

            在之前的blog對Oracle 的記憶體架構也做了一個概述,參考:

            在網上搜到一篇介紹shared pool 非常詳細的pdf資料。 原文連結以找不到,但還是要感謝作者Kamus的辛勤勞動。

            結合Kamus 的pdf和csdn 網友的blog,重新整理了一下,連結如下:

IINTRODUCT IION

            What is shared pool? This first query that comes,let us have a brief introduction regarding shared pool here first.Most of the people knows that shared pool is the part of System Global Area (SGA) it’s true but little else, What exactly the shared pool?

            Shared pool are contain lots of key memory areas of Oracle and in Instance tuning the major area that we have to tune is shared pool if shared pool defined improperly the overall database performance will suffer.

 

            Majority shared pool related to the two part of SGA one is fixed are which is relatively constant to a oracle instance for a particular version and the second part is Variable area which gradually shrink and grow for user and application requirement.

Now we should do a close look of various component of Shared Pool

Basically Shared Pool could be divided in three major parts:

            1. Library Cache

            2. Dictionary Cache

            3. Control Structure

 二.  Library Cache

            Memory Part where all the SQL and PL/SQL statement executed, all execution plan reside here for SQL statement stored here.

We can further subdivide this Library Chache into:

            1. Shared and Private SQL Area

            2. PL/SQL Procedure Part

2.1 Shared and Private SQL Area

            A shared SQL area contains the parse tree and execution plan for a single SQL statement, or for similar SQL statements. Oracle saves memory by using one shared SQL area for multiple similar DML statements, particularly when many users execute the same application.

            A shared SQL area is always in the shared pool. Oracle allocates memory from the shared pool when a SQL statement is parsed; the size of this memory depends on the complexity of the statement. If a SQL statement requires a new shared SQL area and the entire shared pool has already been allocated, Oracle can deallocate items from the pool using a modified least Recently used algorithm until there is enough free space for the new statement's shared SQL area.

             A private SQL area contains data such as bind information and runtime buffers. Each session that issues a SQL statement has a private SQL area. Each user that submits an identical SQL statement has his or her own private SQL area that uses a single shared SQL area; many private SQL areas can be associated with the same shared SQL area.

A private SQL area has a persistent area and a runtime area:

            (1)The persistent area contains bind information that persists across executions, code for datatype conversion (in case the defined datatype is not the same as the datatype of the selected column), and other state information (like recursive or remote

cursor numbers or the state of a parallel query). The size of the persistent area depends on the number of binds and columns specified in the statement. For example, the persistent area is larger if many columns are specified in a query.

            (2)The runtime area contains information used while the SQL statement is being executed. The size of the runtime area depends on the type and complexity of the SQL statement being executed and on the sizes of the rows that are processed by the statement. In general, the runtime area is somewhat smaller for INSERT, UPDATE and DELETE statements than it is for SELECT statements, particularly when the SELECT statement requires a sort.

            Oracle creates the runtime area as the first step of an execute request. For INSERT, UPDATE, and DELETE statements, Oracle frees the runtime area after the statement has been executed.  For queries, Oracle frees the runtime area only after all rows are fetched or the query is cancelled.

            The location of a private SQL area depends on the type of connection established for a session. If a session is connected via a dedicated server, private SQL areas are located in the user's PGA. However, if a session is connected via the multithreaded server, the persistent areas and, for SELECT statements, the runtime areas, are kept in the SGA (x$ksmms) table provide the runtime information regarding SQL area in Library Cache which is suppose to be allocated to a particular Oracle Instance。

E.g.

/* Formatted on 2011/6/21 10:18:48 (QP5 v5.163.1008.3004) */

SELECT *

  FROM X$KSMSS

 WHERE KSMSSNAM = 'sql_area' AND KSMSSLEN <> 0;

 2.2 PL/SQL Procedure Part

            Oracle processes PL/SQL program units (procedures, functions, packages, anonymous blocks, and database triggers) much the same way it processes individual SQL statements.

            Oracle allocates a shared area to hold the parsed, compiled form of a program unit. Oracle allocates a private area to hold values specific to the session that executes the program unit, including local, global, and package variables (also known as package instantiation) and buffers for executing SQL. If more than one user executes the same program unit, then a single, shared area is used by all users, while each user maintains a separate copy of his or her private SQL area, holding values specific to his or her session.

            Individual SQL statements contained within a PL/SQL program unit are processed as described in the previous sections. Despite their origins within a PL/SQL program unit, these SQL statements use a shared area to hold their parsed representations and a private area for each session that executes the statement.

            (x$ksmms) table provide the runtime information regarding PL/SQL area in Library Cache which is suppose to be allocated to a particular Oracle Instance 。

E.g.

/* Formatted on 2011/6/21 10:39:11 (QP5 v5.163.1008.3004) */

SELECT *

  FROM X$KSMSS

 WHERE KSMSSNAM LIKE 'PL/SQL%' AND KSMSSLEN <> 0;

 

PL/SQL MPCODE stands for machine dependent pseudocode.

PL/SQL DIANA stands for the PL/SQL code size in the shared pool at runtime.

2.3  Library Cache Manager

            The main purpose of the library cache is to provide a mechanism to locate and store any library cache object quickly. A hashing mechanism is used to locate a handle, which contains the identity (name) of the object. The library cache handle then points us to one or more the library cache objects and their contents.        

            The library cache caches different types of library objects (e.g. packages, procedures, functions, shared cursors, anonymous PL/SQL blocks, table definitions, view definitions, form definitions).

            Library cache memory is allocated out of the top most heap or the generic SGA heap. When the library cache, KGL, needs more memory, it will call the heap manager (KGH) to allocate it. The library cache consists of a hash table, which consists of an array of hash buckets. Each hash bucket is a doubly linked list of library cache object handles. Each library cache object handle points to a library cache object and has a reference list. The library cache object is further broken down into other components such as a dependency table, a child table, and an authorisation table (to name a few).

KGH Heap Manager 說明:

            Shared pool和PGA都是由一個Oracle的記憶體管理器來管理,我們稱之為KGH heap manager。Heap Manager不是一個程序,而是一串程式碼。Heap Manager主要目的就是滿足server 程序請求memory 的時候分配記憶體或者釋放記憶體。        Heap Manager在管理PGA的時候,Heap Manager需要和作業系統來打交道來分配或者回收記憶體。但是呢,在shared pool中,記憶體是預先分配的,Heap Manager管理所有的空閒記憶體。

            當某個程序需要分配shared pool的記憶體的時候,Heap Manager就滿足該請求,Heap Manager也和其他ORACLE模組一起工作來回收shared pool的空閒記憶體

2.4  Library Cache Manager (Hash Table and Hash Bucket)

            Library cache Manager 可以看做是Heap Manager的客戶端,因為library cache manager是根據Heap Manager來分配記憶體從而存放library cache objects。Library cache Manager控制所有的library cache object,包括package/procedure, cursor, trigger等等。

            Library cache是由一個hash table組成,這個hash table又由hash bucket組成的陣列構成,每個hash bucket又是由一些相互指向的library cache handle所組成,library cache object handle就指向具體的library cache object以及一些引用列表。

            The hash table is an array of hash buckets. The initial number of the hash buckets is 251; however, the number of buckets will increase when the number of objects in the table exceeds the next number.

            The next numbers are the next higher prime value. They are 251, 509, 1021,2039, 4093, 8191, 16381, 32749, 65521, 131071,and 4292967293 where the "n+1"th size is approximately twice the "n"th size. The resulting expansion of the hash table will involve allocating a new hash table at the next prime size, rehashing the library cache objects from the old table to the new table, and freeing the space allocated from the old hash table. Throughout this procedure, access to the hash table is blocked (by freezing access to the child latches) as one user allocates new buckets to double the size of the hash table and then uses the least significant bits of the hash value to determine which new bucket a handle belongs to. Contrary to common belief, this is a rare and inexpensive operation that may cause a short (approximately 3-5 second) hiccup in the system.

            The hash table never shrinks. The library cache manager will apply a modulo hash function to a given object’s namespace, object name, owner, and database link to determine the hash bucket where the object should be found.

            It then walks down the corresponding linked list to see if the object is there. If the object does not exist, the library cache manager will create an empty object with the given name, insert it in the hash table, and request the client load it by calling the client's environment dependent load function.

            Basically, the client would read from disk, call the heap manager to allocate memory, and load the object.

2.5 Library Cache Handle

            A library cache handles points to a library cache object. It contains the name of the library object, the namespace, a timestamp, a reference list, a list of locks locking the object and a list of pins pinning the object. Each object is uniquely identified by the name within its namespace.

            對Library cache中所有物件的訪問是通過利用library cache handle來實現的,也就是說我們想要訪問library cache object,我們必須先找到library cache handle。Library cache handle指向library cache object,它包含了library object的名字,名稱空間,時間戳,引用列表,lock物件以及pin物件的列表資訊等等。

            Library cache handle也被library cache用來記錄哪個使用者在這個這個handle上有lock,或者是哪個使用者正在等待獲得這個lock。那麼這裡我們也知道了library cache lock是發生在handle上的。

    當一個程序請求library cache object, library cache manager就會應用一個hash 演算法,從而得到一個hash 值,根據相應的hash值到相應的hash bucket中去尋找。

            這裡的hash演算法原理與buffer cache中快速定位block的原理是一樣的。如果library cache object在記憶體中,那麼這個library cache handle就會被找到。有時候,當shared pool不夠大,library cache handle會保留在記憶體中,然而library cache heap由於記憶體不足被age out,這個時候我們請求的object heap就會被過載。最壞的情況下,library cache handle在記憶體中沒有找到,這個時候就必須分配一個新的library cache handle,同時object heap也會被載入到記憶體中。

檢視namespace:

[email protected](rac2)> select namespace from v$librarycache;

NAMESPACE

---------------

SQL AREA

TABLE/PROCEDURE

BODY

TRIGGER

INDEX

CLUSTER

OBJECT

PIPE

JAVA SOURCE

JAVA RESOURCE

JAVA DATA

在AWR 裡有關Library Cache Activity 的統計資訊:

 

            Library Cache Object是由一些獨立的heap所組成, Library cache handle指向Library cache Object,其實handle是指向第一個heap,這個heap 我們就稱之為heap 0。Heap 0記錄了指向其他heap的指標資訊。

            The library cache manager will generate a name for every object, even anonymous PL/SQL blocks. The handle uses namespaces to partition library cache objects by types.

             These are examples of different types of namespaces: one namespace holds all namespaces depended on PL/SQL objects, one for package bodies and table bodies, one for shared cursors; one for triggers; one for indexes; and one for clusters. The namespace describes the type of an item kept in the library cache.

            The name consists of the object owner name, the object name, the database link name, and the database link owner name. A comprehensive list can be viewed from v$librarycache.

            A handle can be freed if there are no current references to it and it has not been expressly marked to be kept. We use this to determine when a handle should be unpinned in memory.2.6  Library cache lock/pin

            Library cache lock/pin是用來控制對library cache object的併發訪問的。Lock管理併發,pin管理一致性,lock是針對於library cache handle, 而pin是針對於heap。

            當我們想要訪問某個library cache object,我們首先要獲得這個指向這個object的handle的lock,獲得這個lock之後我們就需要pin住指向這個object的heap。

            當我們對包,儲存過程,函式,檢視進行編譯的時候,Oracle就會在這些物件的handle上面首先獲得一個library cache lock,然後再在這些物件的heap上獲得pin,這樣就能保證在編譯的時候其它程序不會來更改這些物件的定義,或者將物件刪除。

            當一個session對SQL語句進行硬解析的時候,這個session就必須獲得library cache lock,這樣其他session就不能夠訪問或者更改這個SQL所引用的物件。如果這個等待事件花了很長時間,通常表明共享池太小(由於共享池太小,需要搜尋free的chunk,或者將某些可以被移出的object page out,這樣要花很長時間),當然了,也有可能另外的session正在對object進行修改(比如split 分割槽),而當前session需要引用那個table,那麼這種情況下我們必須等另外的session進行完畢。

 Library Cache lock有3中模式:

            (1)Share(S):      當讀取一個library cache object的時候獲得

            (2)Exclusive(X):  當建立/修改一個library cache object的時候獲得

            (3)Null(N):     用來確保物件依賴性

            比如一個程序想要編譯某個檢視,那麼就會獲得一個共享鎖,如果我們要create/drop/alter某個物件,那麼就會獲得exclusive lock。Null鎖非常特殊,我們在任何可以執行的物件(cursor,function)上面都擁有NULL鎖,我們可以隨時打破這個NULL鎖,當這個NULL鎖被打破了,就表示這個物件被更改了,需要從新編譯。

            NULL鎖主要的目的就是標記某個物件是否有效。比如一個SQL語句在解析的時候獲得了NULL 鎖,如果這個SQL的物件一直在共享池中,那麼這個NULL鎖就會一直存在下去,當這個SQL語句所引用的表被修改之後,這個NULL鎖就被打破了,因為修改這個SQL語句的時候會獲得Exclusive 鎖,由於NULL鎖被打破了,下次執行這個SQL的時候就需要從新編譯。

 Library Cache pin有2種模式:

            (1)Share(S):      讀取object heap

            (2)Exclusive(X): 修改object heap

             當某個session想要讀取object heap,就需要獲得一個共享模式的pin,當某個session想要修改object heap,就需要獲得排他的pin。當然了在獲得pin之前必須獲得lock。

             在Oracle10gR2中,library cache pin被library cache mutex 所取代。

 2.7  Library cache Latch

            Library cache latch用來控制對library cache object的併發訪問。前面已經提到,我們要訪問library cache object之前必須獲得library cache lock, lock不是一個原子操作(原子操作就是在操作程中不會被打破的操作,很明顯這裡的lock可以被打破), Oracle為了保護這個lock,引入了library cache latch機制,也就是說在獲得library cache lock之前,需要先獲得library cache latch,當獲得library cache lock之後就釋放library cache latch。

            如果某個library cache object沒有在記憶體中,那麼這個lock就不能被獲取,這個時候需要獲得一個library cache load lock latch,然後再獲取一個library cache load lock,當load lock獲得之後就釋放library cache load lock latch。

            library cache latch受隱含引數_KGL_LATCH_COUNT的控制,預設值為大於等於系統中CPU個數的最小素數,但是Oracle對其有一個硬性限制,該引數不能大於67。

            注意:我們去查詢_kgl_latch_count有時候顯示為0,這是一個bug。

Oracle利用下面演算法來確定library cache object handle是由哪個子latch來保護的:

            latch# = mod(bucket#, #latches)

            也就是說用哪個子latch去保護某個handle是根據那個handle所在的bucket號,以及總共有多少個子latch來進行hash運算得到的。

三.  Dictionary Cache

            Table definition against which an application user suppose to do a query, it include table’s associated Index and Columns and privilege information regarding table as we as columns.

/* Formatted on 2011/6/21 15:01:52 (QP5 v5.163.1008.3004) */

SELECT *

  FROM X$KSMSS

 WHERE KSMSSNAM LIKE 'PL/SQL%' AND KSMSSLEN <> 0;

四.  Control Structure

            This contain the information regarding Internal Latch and Locks (Data Structure), it also contain buffer header, the process session and transaction arrays.

            The size of these arrays depends on the setting of Initialisation parameter of Init.ora file and can’t be changed without shutting down the database.

4.1 Shared Pool Chunks

            Have close looks of Shared Pool, For that we should have a close look at x$ksmsp each row in this table shows a chunk of shared pool :

SQL>select * from X$ksmsp

            When each shared pool chunk is allocated the code is passed to a function that does the work of allocation and this address is visible to KSMCHCOM column,which describe the purpose of allocation. This chunk is supposed to be larger then the size of the object as it also contains the header information.

             The column KSMCHCLS represent the class, there are basically four type of classes:

            Freeabl :  can be freed only contain the objects needed for the session call.

            Free :  free and not contained by valid object.

            Recr :  contain by temporary objects.

            Perm :  contained by the permanent object.

/* Formatted on 2011/6/21 16:14:50 (QP5 v5.163.1008.3004) */

  SELECT KSMCHCLS CLASS,

         COUNT (KSMCHCLS) NUM,

         SUM (KSMCHSIZ) SIZ,

         TO_CHAR ( ( (SUM (KSMCHSIZ) / COUNT (KSMCHCLS) / 1024)), '999,999.00')

         || 'k'

            "AVG SIZE"

    FROM X$KSMSP

GROUP BY KSMCHCLS;

注意:

            在生產庫上查詢X$KSMSP時,要看下系統的繁忙或者說是負載高低,因為可能會導致db hang 住。

So the overall summary :

/* Formatted on 2011/6/21 16:06:38 (QP5 v5.163.1008.3004) */

  SELECT KSMCHCOM name,

         COUNT (KSMCHCOM),

         SUM (DECODE (KSMCHCLS, 'recr', KSMCHSIZ)) RECREATABLE,

         SUM (DECODE (KSMCHCLS, 'freeabl', KSMCHSIZ)) FREEABLE

    FROM x$ksmsp

GROUP BY KSMCHCOM;

4.2 LRU List

            When a process starts it allocate some memory and when it’ fails to allocated required memory, Then it try to remove chunk containing recreatable object from shared pool to get the desired size of chunk, and removing these object from memory is based on LRU(Least Recent Used) means those objects that are frequently pinned kept in the memory and those are unpinned we generally remove those objects from the memory. Object those required again known as transient and other known as recurrent.

ORA-04331 ‘unable to allocate x bytes of shared pool’ when all the free memory fully exhausted (Later we will discuss the shared pool fragmentation).

            There is one list maintained which known as Reserved List, it generally 5% of the total size of Shared Pool and reserved size is defined by SHARED_POOL_RESERVED_SIZE parameter in Init.ora parameter file.

            With the help of v$shared_pool_reserved we can see reserved size, here REQUEST_MISS shows the number of times the request miss for a large chunk.

4.3 SHARED_POOL size calculation

            The shared pool size is highly application dependent. To determine the shared pool size for a production system it is generally necessary to develop the application run it on a test environment (should be enough like production system) get some test result and on the basis of that calculate the shared pool size. There are some few step which we should consider while calculating the shared pool:

4.3.1 STORED OBJECTS

            The amount of shared pool that needs to be allocated for objects that are stored in the database like packages and views is easy to measure. You can just measure their size directly with the following statement:

/* Formatted on 2011/6/21 16:32:28 (QP5 v5.163.1008.3004) */

SELECT SUM (sharable_mem) FROM V$DB_OBJECT_CACHE;

4.3.2 SQL

            The amount of memory needed to store sql statements in the shared pool is more difficult to measure because of the needs of dynamic sql. If an application has no dynamic sql then the amount of memory can simply be measured after the application has run for a while by just selecting it out of the shared pool as follows:

/* Formatted on 2011/6/21 16:34:02 (QP5 v5.163.1008.3004) */

SELECT SUM (sharable_mem) FROM v$sqlarea;

            If the application has a moderate or large amount of dynamic sql like most applications do, then a certain amount of memory will be needed for the shared sql plus more for thedynamic sql. Sufficient memory should be allocated so that the dynamic sql does not age the shared sql out of the shared pool.

            Approximated memory could be calculated by the following:

/* Formatted on 2011/6/21 16:35:06 (QP5 v5.163.1008.3004) */

SELECT SUM (sharable_mem)

  FROM v$sqlarea

 WHERE executions > 5;

The remaining memory in v$sqlarea is for dynamic sql.

4.3.3 PER-USER PER-CURSOR MEMORY

            You will need to allow around 250 bytes of memory in the shared pool per concurrent user for each open cursor that the user has whether the cursor is shared or not. During the peak usage time of the production system, you can measure this as follows:

/* Formatted on 2011/6/21 16:36:55 (QP5 v5.163.1008.3004) */

SELECT SUM (250 * users_opening) FROM v$sqlarea;

            In a test system you can measure it by selecting the number of open cursors for a test user and multiplying by the total number of users:

/* Formatted on 2011/6/21 16:37:20 (QP5 v5.163.1008.3004) */

SELECT 250 * VALUE bytes_per_user

  FROM v$sesstat s, v$statname n

 WHERE     s.statistic# = n.statistic#

       AND n.name = 'opened cursors current'

       AND s.sid = 130;

-- replace 130 with session id of user being measured

            The per-user per-cursor memory is one of the classes of memory that shows up as 'library cache' in v$sgastat.

4.3.4 MTS

            If you are using multi-threaded server, then you will need to allow enough memory for all the shared server users to put their session memory in the shared pool.            This can be measured for one user with the following query:

/* Formatted on 2011/6/21 16:39:31 (QP5 v5.163.1008.3004) */

SELECT VALUE sess_mem

  FROM v$sesstat s, v$statname n

 WHERE     s.statistic# = n.statistic#

       AND n.name = 'session uga memory'

       AND s.sid = 23;

-- replace 23 with session id of user being measured

            A more conservative value to use is the maximum session memory that was ever allocated by the user:

/* Formatted on 2011/6/21 16:40:22 (QP5 v5.163.1008.3004) */

SELECT VALUE sess_max_mem

  FROM v$sesstat s, v$statname n

 WHERE     s.statistic# = n.statistic#

       AND n.name = 'session uga memory max'

       AND s.sid = 23;

-- replace 23 with session id of user being measured

            To select this value for all the currently logged on users the following query can be used:

/* Formatted on 2011/6/21 16:40:56 (QP5 v5.163.1008.3004) */

SELECT SUM (VALUE) all_sess_mem

  FROM v$sesstat s, v$statname n

 WHERE s.statistic# = n.statistic# AND n.name = 'session uga memory max';

4.3.5 OVERHEAD

            You will need to add a minimum of 30% overhead to the values calculated above to allow for unexpected and unmeasured usage of the shared pool.

Estimating Procedure (From Metalink)

/* Formatted on 2011/6/21 16:46:24 (QP5 v5.163.1008.3004) */

SET SERVEROUTPUT ON;

DECLARE

   object_mem       NUMBER;

   shared_sql       NUMBER;

   cursor_mem       NUMBER;

   mts_mem          NUMBER;

   used_pool_size   NUMBER;

   free_mem         NUMBER;

   pool_size        VARCHAR2 (100);

BEGIN

   -- Stored objects (packages, views)

   SELECT SUM (sharable_mem) INTO object_mem FROM v$db_object_cache;

   -- Shared SQL -- need to have additional memory if dynamic SQL used

   SELECT SUM (sharable_mem) INTO shared_sql FROM v$sqlarea;

   -- User Cursor Usage -- run this during peak usage

   SELECT SUM (250 * users_opening) INTO cursor_mem FROM v$sqlarea;

   -- For a test system -- get usage for one user, multiply by # users

   -- select (250 * value) bytes_per_user

   -- from v$sesstat s, v$statname n

   -- where s.statistic# = n.statistic#

   -- and n.name = 'opened cursors current'

   -- and s.sid = 25; -- where 25 is the sid of the process

   -- MTS memory needed to hold session information for shared server users

   -- This query computes a total for all currently logged on users (run

   -- during peak period). Alternatively calculate for a single user and

   -- multiply by # users.

   SELECT SUM (VALUE)

     INTO mts_mem

     FROM v$sesstat s, v$statname n

    WHERE s.statistic# = n.statistic# AND n.name = 'session uga memory max';

   -- Free (unused) memory in the SGA: gives an indication of how much memory

   -- is being wasted out of the total allocated.

   SELECT bytes

     INTO free_mem

     FROM v$sgastat

    WHERE name = 'free memory';

   -- For non-MTS add up object, shared sql, cursors and 30% overhead.

   used_pool_size := ROUND (1.3 * (object_mem + shared_sql + cursor_mem));

   -- For MTS add mts contribution also.

   -- used_pool_size := round(1.3*(object_mem+shared_sql+cursor_mem+mts_mem));

   SELECT VALUE

     INTO pool_size

     FROM v$parameter

    WHERE name = 'shared_pool_size';

   -- Display results

   DBMS_OUTPUT.put_line ('Obj mem: ' || TO_CHAR (object_mem) || ' bytes');

   DBMS_OUTPUT.put_line ('Shared sql:' || TO_CHAR (shared_sql) || ' bytes');

   DBMS_OUTPUT.put_line ('Cursors: ' || TO_CHAR (cursor_mem) || ' bytes');

   DBMS_OUTPUT.put_line ('MTS session:' || TO_CHAR (mts_mem) || ' bytes');

   DBMS_OUTPUT.put_line (

         'Free memory:'

      || TO_CHAR (free_mem)

      || ' bytes '

      || '('

      || TO_CHAR (ROUND (free_mem / 1024 / 1024, 2))

      || 'M)');

   DBMS_OUTPUT.put_line (

         'Shared poolutilization (total): '

      || TO_CHAR (used_pool_size)

      || ' bytes '

      || '('

      || TO_CHAR (ROUND (used_pool_size / 1024 / 1024, 2))

      || 'M)');

   --Technical Reports Compendium, Volume I, 1996

   --Shared Pool Internals

   DBMS_OUTPUT.put_line (

         'Shared pool allocation (actual): '

      || pool_size

      || ' bytes'

      || '('

      || TO_CHAR (ROUND (pool_size / 1024 / 1024, 2))

      || 'M)');

   DBMS_OUTPUT.put_line (

         'Percentage Utilized:'

      || TO_CHAR (ROUND (used_pool_size / pool_size * 100))

      || '%');

END;

五. Monitoring & Tuning

            Let begin with major part which is knows as shared pool tuning and Oracle recommend that the default size of Shared Pool in Init.ora parameter should be ¼ of the Total SGA in a general scenario.

            The other shared pool parameter controls how to the variable space area in the shared pool is parsed out. According to the suggestion give by Oracle if our total SGA size is 100 MB then we should set our Shared Pool size 25 MB and latter increase gradually as needed by the system.

            Now a question comes in our mind what are the key area should be monitored by the DBA to get the knowledge that the shared pool size is small.

            From V$SGASTAT and V$SQLAREA we will get this information.

            how we can see that what is in the shared pool? Whether is being properly used or not. For that we can generate some common useful report.

First report will shown here the individual mapping of user with shared pool:

            Create a temporary table to hold the information related to sql area for all users,that produces a summary report for each user.

/* Formatted on 2011/6/22 0:16:26 (QP5 v5.163.1008.3004) */

CREATE TABLE TEMP_SQL_REPORT

AS

   (SELECT B.USERNAME,

           A.SQL_TEXT,

           A.EXECUTIONS,

           A.LOADS,

           A.USERS_EXECUTING,

           A.SHARABLE_MEM,

           A.PERSISTENT_MEM,

           A.RUNTIME_MEM

      FROM V$SQLAREA A, DBA_USERS B

     WHERE A.PARSING_USER_ID = B.USER_ID)

檢視report:

/* Formatted on 2011/6/22 0:19:04 (QP5 v5.163.1008.3004) */

  SELECT Username,

         SUM (SHARABLE_MEM),

         SUM (PERSISTENT_MEM),

         SUM (RUNTIME_MEM)

    FROM temp_sql_report

GROUP BY username;

 

            This output of this summary report shows here the sql area used by each user. Now try to analyse the summary report, if a particular hold a large amount of memory then that means the sql’s used by that user are bad every time it generate different execution plan for similar kind of queries, the coding produce a large number of nonreusable sql area.

            Now we can generate an another where we will shown the actual sql statement executed by a user and how many time a sql statement execute by a user , what amount of memory that sql statement took to execute the statement.

/* Formatted on 2011/6/22 0:25:30 (QP5 v5.163.1008.3004) */

  SELECT username users,

         sql_text,

         Executions,

         loads,

         users_executing,

         sharable_mem,

         persistent_mem

    FROM temp_sql_report b

   WHERE b.username LIKE UPPER ('%&user_name%')

ORDER BY 3 DESC, 1;

5.1 SQL

5.1.1  Literal SQL

            A literal SQL statement is considered as one which use literals in the predicates rather then bind variable, where the value of the literal is likely to differ between various execution of the statement.

E.g 1 :

SELECT * FROM temp_x WHERE col_1='x';

is used by the application instead of

SELECT * FROM temp_x WHERE ename=:x;

Eg 2:

SELECT sysdate FROM dual;

            does not use bind variables but would not be considered as a literal SQL statement for this article as it can be shared.

Eg 3:

SELECT version FROM app_version WHERE version>2.0;

            If this same statement was used for checking the 'version' throughout the application then the literal value '2.0' is always the same so this statement can be considered sharable.

5.1.2 Hard Parse

            If a new SQL statement is issued which does not exist in the shared pool then this has to be parsed fully. Eg: Oracle has to allocate memory for the statement from the shared pool, check the statement syntactically and semantically etc...

            This is referred to as a hard parse, is very expensive in both terms of CPU used, and in the number of latch get s performed.

5.1.3 Soft Parse

            If session issues a SQL statement, which is already in the shared pool AND it, can use an existing version of that statement then this is known as a 'soft parse'. As far as the application is concerned it has asked to parse the statement.

5.1.4 Identical Statements

            If two SQL statements mean the same thing but are not identical character for character then from an Oracle viewpoint they are different statements. Consider the following issued by

            SCOTT in a single session:

                        SELECT ENAME from TEMP_X;

                        SELECT ename from temp_x;

            Although both of these statements are really the same they are not identical as an upper case 'T' is not the same as a lower case 't'.

5.1.5 Sharable SQL

            If two sessions issue identical SQL statements it does NOT mean that the statement is sharable. Consider the following:

User USER_X has a table called TEMP_X and issues:

            SELECT column_x from TEMP_X;

User USER_Y has his own table called TEMP_X and also issues:

            SELECT column_y from TEMP_X;

            Although the text of the statements are identical the TEMP_X tables are different objects. Hence these are different versions of the same basic statement. There are many things that determine if two identical SQL strings are truly the same statement (and hence can be shared) including:

            All object names must resolve to the same actual objects. The optimiser goal of the sessions issuing the statement should be the same The types and lengths of any bind variables should be "similar". (We don’t discuss the details of this here but different types or lengths of bind variables can cause statements to be classed as different versions). The NLS (National Language Support) environment which applies to the statement must be the same

5.1.6 Versions of a statement

            As described in 'Sharable SQL' if two statements are textually identical but cannot be shared then these are called 'versions' of the same statement.

            If Oracle matches to a statement with many versions it has to check each version in turn to see if it is truly identical to the statement currently being parsed. Hence high version counts are best avoided by:

            Standardising the maximum bind lengths specified by the client Avoid using identical SQL from lots of different schemas, which use private objects.

Eg:

            SELECT xx FROM MYTABLE;

where eachuser has their own MYTABLE

            Setting _SQLEXEC_PROGRESSION_COST to '0' in Oracle 8.1

5.1.7 Library Cache and Shared Pool latches

            The shared pool latch is used to protect critical operations when allocating and freeing memory in the shared pool.

            The library cache latches (and the library cache pin latch in Oracle 7.1) protect operations within the library cache itself. All of these latches are potential points of contention. The number of latch gets occurring is influenced directly by the amount activity in the shared pool, especially parse operations. Anything that can minimise the number of latch gets and indeed the amount of activity in the shared pool is helpful to both performance and scalability.

5.1.8 Literal SQL versus Shared SQL

            To give a balanced picture this short section describes the benefits of both literal SQL and sharable SQL.

5.1.8.1 Literal SQL

            The Cost Based Optimiser (CBO) works best when it has full statistics and when statements use literals in their predicates. Consider the following:

            SELECT distinct cust_ref FROM orders WHERE total_cost < 10000.0;

Versus

            SELECT distinct cust_ref FROM orders WHERE total_cost < :bindA;

            For the first statement the CBO could use histogram statistics that have been gathered to decide if it would be fastest to do a full table scan of ORDERS or to use an index scan on TOTAL_COST (assuming there is one).

            In the second statement CBO has no idea what percentage of rows fall below ":bindA" as it has no value for this bind variable to determine an execution plan . Eg: ":bindA" could be 0.0 or 99999999999999999.9

            There could be orders of magnitude difference in the response time between the two execution paths so using the literal statement is preferable if you want CBO to work out the best execution plan for you. This is typical of Decision Support Systems where there may not be any 'standard' statements, which are issued repeatedly so the chance of sharing a statement is small. Also the amount of CPU spent on parsing is typically only a small percentage of that used to execute each statement so it is probably more important to give the optimiser as much information as possible than to minimise parse times.

5.1.8.2 Sharable SQL

            If an application makes use of literal (unshared) SQL then this can severely limit scalability and thr oughput. The cost of parsing a new SQL statement is expensive both in terms of CPU requirements and the number of times the library cache and shared pool latches may need to be acquired and released.

            Eg: Even parsing a simple SQL statement may need to acquire a library cache latch 20 or 30 times.

            The best approach to take is that all SQL should be sharable unless it is adhoc or infrequently used SQL where it is important to give CBO as much information as possible in order for it to produce a good execution plan. Reducing the load on the Shared Pool

5.1.9 Parse Once / Execute Many

            By far the best approach to use in OLTP type applications is to parse a statement only once and hold the cursor open, executing it as required. This results in only the initial parse for each statement (either soft or hard). Obviously there will be some statements which are rarely executed and so maintaining an open cursor for them is a wasteful overhead.

            Note that a session only has < Parameter: OPEN_CURSORS> cursors available and holding cursors open is likely to increase the total number of concurrently open cursors.

            In precompilers the HOLD_CURSOR parameter controls whether cursors are held open or not while in OCI developers have direct control over cursors.

5.1.10 Eliminating Liter al SQL

            If you have an existing application it is unlikely that you could eliminate all literal SQL but you should be prepared to eliminate some if it is causing problems. By looking at the V$SQLAREA view it is possible to see which literal statements are good candidates for converting to use bind variables. The following query that shows SQL in the SGA where there are a large number of similar statements:

/* Formatted on 2011/6/22 10:51:28 (QP5 v5.163.1008.3004) */

  SELECT SUBSTR (sql_text, 1, 40) "SQL", COUNT (*), SUM (executions) "TotExecs"

    FROM v$sqlarea

   WHERE executions < 5

GROUP BY SUBSTR (sql_text, 1, 40)

  HAVING COUNT (*) > 30

ORDER BY 2;


            Note: If there is latch contention for the library cache latches the above Statement may cause yet further contention problems.

            The values 40,5 and 30 are example values so this query is looking for different statements whose first 40 characters are the same which have only been executed a few times each and there are at least 30 different occurrences in the shared pool.

            This query uses the idea it is common for literal statements to begin "SELECT col1, col2, col3 FROM table WHERE..." with the leading portion of each statement being the same.

            Note: There is often some degree of resistance to converting literal SQL to use bind variables. Be assured that it has been proven time and time again that performing this conversion for the most frequently occurring statements can eliminate problems with the shared pool and improve scalability greatly.

5.1.11 Performance Effects

            Oracle performance can be severely compromised by large volumes of literal SQL. Some of the symptoms that may be noticed are:

(1).  System is CPU bound and exhibits an insatiable appetite for CPU.

(2).  System appears to periodically “hang” after some period of normal operation.

(3).  Latch contention on shared pool and library cache latches.

(4).  Increasing the shared pool size delays the problem but it re-occurs more severely.

5.1.12  Identifying the Problem

            An Oracle instance suffering f