Shared Pool Internals

58
Technical Reports Compendium, Volume I, 1996 Shared Pool Internals ORACLE CONFIDENTIAL, Release 7.3 4-1 Shared Pool Internals OR Swimming Without a Life Jacket: A Dive into the Shared Pool Lawrence To Roderick Manalac Center of Expertise Worldwide Customer Support Oracle Corporation

Transcript of Shared Pool Internals

Page 1: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-1

Shared Pool Internals

ORSwimming Without a Life Jacket: A Dive into the Shared Pool

Lawrence ToRoderick Manalac

Center of ExpertiseWorldwide Customer Support

Oracle Corporation

Page 2: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-2 ORACLE CONFIDENTIAL , Release 7.3

Page 3: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-3

SECTION ONE: INTRODUCTION........................................................................................................................................4

SECTION TWO: OVERVIEW................................................................................................................................................5

HISTORY......................................................................................................................................................................................5 MEMORY MANAGEMENT.............................................................................................................................................................6

SECTION THREE: THE COMPONENTS OF THE ORACLE MEMORY ARCHITECTURE .....................................8

PGA ............................................................................................................................................................................................8 SGA ............................................................................................................................................................................................8 CLASSES ...................................................................................................................................................................................9

SECTION FOUR: LIBRARY CACHE MANAGER ...........................................................................................................12

CONCEPTS..................................................................................................................................................................................12 HASH TABLE AND HASH BUCKET..............................................................................................................................................12 LIBRARY CACHE HANDLE..........................................................................................................................................................13 LIBRARY CACHE OBJECT...........................................................................................................................................................14 LOCKING AND PINNING ..............................................................................................................................................................16 LIBRARY CACHE LATCHES........................................................................................................................................................18

SECTION FIVE: TUNING AND MONITORING THE SHARED POOL........................................................................19

INTRODUCTION ....................................................................................................................................................................19 QUICK TUNING TIPS ............................................................................................................................................................19 MEMORY FRAGMENTATION .............................................................................................................................................21 LIBRARY CACHE LATCH CONTENTION..........................................................................................................................26 SIZING OF SHARED POOL ...................................................................................................................................................28 COMMON FALLACIES..........................................................................................................................................................31 SUMMARY..............................................................................................................................................................................32 MONITORING AND V$VIEWS.............................................................................................................................................32 SCRIPTS AND INIT.ORA PARAMETERS............................................................................................................................35 RESERVED SHARED POOL..........................................................................................................................................................51 TUNING HINTS BASED ON V$SHARED_POOL_RESERVED .........................................................................................53 PROCEDURE FREE_UNUSED_MEMORY.......................................................................................................................................54

SECTION SIX: SHARED POOL BUGS...............................................................................................................................57

Page 4: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-4 ORACLE CONFIDENTIAL , Release 7.3

Section One: IntroductionThis is the first of several white papers on the shared pool. Because of the high desire within support to have moreinformation about the shared pool quickly, we are releasing this preliminary paper. Since this is an early version, we ask thatthis paper (with the exception of the tuning scripts in the last section) be kept for support reference only. We will work onproviding even more details about the shared pool, library cache, and the heap manager in the next major release of thispaper. It will likely be accompanied by a reorganization of the contents. Please contact the authors with any corrections,suggestions, or questions that you would like to see integrated into the next version.

One of the major architectural changes introduced in Oracle 7 is the shared pool component of the SGA. It came along withlittle documentation about taking proper care of it and only had one tunable parameter directly associated with it. As a result,most people at best only have a murky view of what is really going on beneath the surface. Every so often they will seecreatures lurking around down there, and get bitten with an ORA-4031 or memory leak error. In the interim, pieces ofadvice on how to avoid drowning have been offered. This paper will attempt to centralize those pieces of information. Inaddition, we wish to shed some light on the inner workings of this structure and show how it relates to the rest of themechanisms involved in processing user requests.

For purposes of simplification we have deferred detailed discussion of how the shared pool relates to Multithreaded Servers(MTS) and the Parallel Query Option (PQO) to a future date. We also do not offer any radical new advice on how to performcapacity planning of the shared pool in this edition of the paper.

This paper will start with a high level view of memory management and work its way down to the actual data structures thatreside within the Oracle shared pool. It is sort of like a National Geographic special with Jacques Cousteau taking his shipCalypso from the surface of the ocean down to the coral reefs below and discovering an whole new ecosystem. We hope youenjoy the adventure with us.

This paper has been created as an instructional outline for members of support. It comprises of a collection of work fromdifferent developers and can be used as a resource in understanding and debugging heap managment and library cacheproblems.

Page 5: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-5

Section Two: Overview

History

Before Oracle7, every Oracle session had a unique process or server associated with it. This server was responsible forparsing and optimizing all SQL and PL/SQL submitted by the client. Typically in OLTP environments, these statementswritten by the end user in an ad-hoc manner; rather they were hard-coded or generated by an application. As the number ofusers of a particular application grew, Oracle became aware that the servers were duplicating much of their efforts. Oraclebelieved that some time and resources could be saved if output of these efforts could be shared. Initially, Oracle examinedhow PL/SQL (especially stored PL/SQL - a new feature in Oracle7) could be better shared but later widened the scope toinclude other objects such as cursors. The desired result was that space would be saved by having one copy of a storedPL/SQL object available for all to share. Also, time would be saved if an execution plan and other pieces of informationwere made available to all servers executing the same SQL.

Note: the concept was expanded further to allow a large number of sessions to be serviced by a small number of servers.

This requires having an initial area to store objects that can be shared, devising a way of managing those objects, and havinga mechanism to allocate and deallocate memory for those objects. Oracle accomplished these objectives by revising threethings:1. The variable portion of the SGA was expanded2. A method to manipulate and access shared objects in the variable portion of the SGA3. Generic Oracle memory management was enhanced

Before we get into the details of how those three items were done, we will provide some background into how memorymanagement works in general. We then explain how Oracle attempts to genericize and optimize usage of the memory that ituses.

Page 6: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-6 ORACLE CONFIDENTIAL , Release 7.3

Memory Management

Memory management will vary widely from operating system to operating system. Basically, most have a concept of virtualmemory addressing. There usually is a memory manager that determines how executable code is laid out across an addressspace and where memory is allocated from when requested. OS memory managers also provide to varying degrees somelevel of protection to prevent threads of execution (e.g. Unix processes) from reading or writing memory allocated to anotherthread. It may also delineate user space from system space. But it also allows applications to share memory if it determinesthere is memory that can be safely shared by multiple threads.

There is a set of operating system dependent code routines (OSD’s) and low level services that Oracle provides so that themajority of Oracle server code can remain generic across all platfoms. One of these low level services is the generic memoryservices. These services work with the OSD’s to allow for creation, destruction, and management of memory that is privateto a thread and memory that will be public to all Oracle threads.

Oracle Layout on UnixWith this in mind, lets dive into an example of how Oracle process memory is laid out for a particular UNIX platform.

Figures in Chapter 1 of the Oracle7 Server Concepts Manual presents a fairly nice view of the Oracle system architecture. Itrelates the main memory structure of Oracle (the SGA) with the various processes that attach to it. The PGA is not displayeduntil Chapter 9. Meanwhile, slightly different representations of this view appear in Chapter 1 of the Oracle7 Server forUnix Administrator's Reference Guide (R7.1). It extends our picture by displaying the concept of single task versus two taskarchitectures and including a picture that associates the PGA with a specific dedicated server process. Chapter 2 of theUnderstanding SQL*Net Guide (V2.1) presents us with a more detailed view of how the two task architecture is laid out.Finally, Chapter 2 of the Programmer's Guide to the Oracle Call Interfaces (R7.1) shows a view of the client cursor area. Italso discusses the dynamics of communications that transpire between client and server when processing a SQL statement.

Figure 1 is an ambitious attempt to combine these concepts into a memory representation of the typical Oracle session in aUnix two-task environment.

In this example, at the lowest address is the actual compiled code of the program.

Notes: the compiled code can be broken up into several sections including a text section that is shared by all processes executing the sameprogram. This code is made up of several modules maintained by different development groups within Oracle. For example the SQL*Netmodule is only responsible for transporting data back and forth between client and server. The data itself is composed of user requests anddata replies that are created by the other modules. Another aside: the client picture actually shows how three separate applications wouldintegrate with the Oracle user program interface (UPI) via different layers of code.

At the high addresses, the operating system keeps tracks which routine the process is currently in and which calling routineto return to. Just above the code section is the operating system managed heap space or the memory that is allocated for useby the program. For example, a UNIX procss can allocate more space for itself with a malloc system call. Oracle callsmalloc/free to resize the PGA when necessary.

The remaining memory section to be discussed is the SGA or shared global area. It is really a piece of memory that is sharedby multiple threads of execution. All servers attach the same piece of memory to the same virtual address space. It iswithin the SGA that the shared pool resides.

Page 7: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-7

S G A(Shared Pool ,

Buffer Cache, etc.)

P G A(UGA, CGA, e tc . )

Process Cal lS tack

Orac le RDBMS

OPI

T T C

SQL*Net

Stack

SharedMemory

O.S.Heap

CodeandData

OCI Pro*C

SQLL IBOCIL IB

UPI

T T C

SQL*Net

SQ

L*P

lus

P rocess Cal lS tack

User/Cl ient Server

LDA & CDA

A D D R E S S S P A C E

Figure 1.

Note: On UNIX, client and server are two separate processes; each with its own address space. Only the server will attach to theSGA. Other operating systems such as VMS allows you to link the applications into a single task executable safely because the OSprovides feature to protect portion of memory from being modified by application specific code. If that protection was not present, thenOracle client code that is linked single task can directly address and change contents of Oracle shared memory segments leading tocorruption of internal Oracle data structures.

Page 8: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-8 ORACLE CONFIDENTIAL , Release 7.3

Section Three: The components of the Oracle Memory Architecture

What exactly are the SGA and PGA? We need to express the answer in terms of why they are needed, when they areallocated, what they are used for, and how they are managed. The purpose of the next section attempts to answer thisquestion.

The RDBMS memory is built on top of two memory structures: the PGA and the SGA. In other words, Oracle abstracts thememory it uses into the PGA or SGA.

PGA

PGA, process global area or private global area, is memory needed for the operation of one process. There is one (and onlyone) independent PGA for each process in an instance. An initial portion, fixed PGA, is allocated at process startup and itwill expand and contract dynamically. Once the process terminates, PGA memory is returned to the operating system.

For security reasons, information need only be seen or modified by a particular process is kept private within that thread ofexecution. Oracle assumes serveral things about private memory: 1) no other process can access it , and the 2) client sideroutines can not access it directly.

SGA

Consequently, for performance reasons there may be data that is better to be shared than to have all threads maintain aprivate copy. In other words, accessing data that is already cached in a public memory area is faster than performing disk IOor executing a similar set of instructions to create a private version of the data. The other advantage is that it decreasesunnecessary memory usage by moving immutable memory structures that are common to several processes into sharedmemory which is found the shared pool.. It attempts to share as much as one can and to make memory allocation moreflexible and easy to use for the server processes. For this, Oracle requires a piece of memory that it assumes to be sharableby all processes within that instance. For example, several processes executing the same sql statement can share the sameexecution plan and avoid unnecessary reoptimization. It also assumes that this memory will be available for use as long asthe instance is running. The SGA, shared global area, is created during instance startup and is deallocated at shutdown.Thereby, it does not dynamically change in size during its lifetime.

For each instance, there is one SGA which each process attaches to a fix address. [note: this is due to Oracle referencingobjects by their virtual address rather than by an offset into SGA] The SGA is composed of four regions (fixed data structuresize, shared pool, database block buffers, redo buffer- see figure 3).

The size of the fixed portion is not controlled by the user and consists of fixed Oracle data structures. On the other hand, thevariable “SGA” size is determined by shared pool size and memory needed to store structures such as handles, enqueues,state objects, etc. Finally db block buffers and redo buffer constitute the last two major structures in the SGA and do not fallwithin the scope of this paper.

Page 9: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-9

Fixed Data Structures

Top SGA Heap(shared pool)

Data Block Buf fers

Log Buffer

Tota l System Global Area 4435156 bytes

Fixed Size 47152 bytes

Var iable Size 3970212 bytes

Database Buf fers 409600 bytes

Redo Buf fers 8192 bytes

S G A

figure 3

CLASSES

Oracle operations allocate space for the data it uses in either the PGA or SGA. The memory location is determined by acouple of factors: 1) whether the data is private or public and 2) the period of time the data is needed (a.k.a. its expectedlifetime or persistence). There are 4 different lifetimes: call, session, process, and instance.

A call’s lifetime is basically the time needed to execute an Oracle Programmatic Interface (OPI) call. Memory that onlyneeds to exist for the lifetime of a call and is private can be placed into PGA. In particular into an area called the CGA, callglobal area. Examples include memory used for DDL operations, DML operations, local PL/SQL variables, and sorting data.It just happens that these are not calls which data needs to be public.

A session’s lifetime lasts from the time a client connects to the database until it disconnects. Data used by a session persistsfor the duration of a session or when the user logs out. Examples are NLS parameters, optimizer goals, sql_trace, altersession information, PLS 2.0 package global states, cursor states, and other "login" data structures (used for security). Wecall the area that where the data is stored the User Global Area (UGA). For MTS and XA, it is necessary for user data to bepublic in the SGA because different servers may need to access such data during the lifetime of the session. Otherwise, it issufficient for the UGA to be private and part of the PGA.

A process’ lifetime lasts from the time a process is started until it dies. Memory used by a process is considered private andtherefore part of the PGA. Examples are the fixed PGA, CGA, and sometimes the UGA (as mentioned above).

Finally the lifetime of an instance is from the time a startup nomount is issued until shutdown or crash. Memory for data thatexists for the lifetime of an instance is generally public. The database buffer cache, log buffer, and shared pool are examplesof SGA memory areas.

Based on knowledge of how long a data structure is needed and whether it needs to be public or private, one can guess atwhere memory for that stucture will be allocated. An exercise for the reader is to figure out why session information isfound in the shared pool or SGA when MTS is enabled.

Page 10: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-10 ORACLE CONFIDENTIAL , Release 7.3

LogBuffers

Variable SizeSGA

(Shared Pool)

DB BlockBuffers

S G A

U G A C G A

P G A

persists unt i l the instanceshutdown or crash

cal l persistsunt i l complet ion

nls data persists unti lsess ion d isconnects

Pers is tence Classes

Persists unti lprocess d ies

Fixed DataStructures

This picture gives examples of what can be found in the PGA and SGA and the life span of data.

Note: The UGA is contained in the SGA (shared pool) when MTS is enabled.

What is the shared pool?

The shared pool is a component of the SGA. This implies it is public and accessible to all server processes and the structurescan have a life span of the instance. The contents have a potential life span greater than the process that created it. Amongother things, shared cursors, PL/SQL objects can be found in the shared pool. There are primary two components of theshared pool not including the overhead: the row cache (also called the dictionary cache), and the library cache.

The row cache contains a in memory version of portions of the data dictionary. For performance reasons, it may containother derived columns.

The library cache is in memory collection of shared objects that can be referenced by any server process. This cachecontains the majority of shared objects such as packages, procedures, shared cursors, tables, views, and other dependencies.Server processes can reference any accessible material (objects).

Note: the overhead contains buffer cache descriptors, handles, enqueues, state objects, etc.

Page 11: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-11

How is it managed?

The shared pool and the PGA are managed by a generic Oracle memory manager, often referred to the KGH heap manager.Heap manager is not a process but a piece a code that is executed by all threads of execution when needed.

The heap manager’s main purpose is to accomodate server process memory requests and to “free” memory when required.It’s generic across all requests and it hides operating system dependencies. For the PGA, it may interact with the operatingsystem to allocate (e.g., malloc/sbrk system call) or free memory (e.g., free system call). However in the shared pool,memory is allocated upfront and the heap manager manages all free space, gives space to accomodate requests, and workswith other Oracle software modules to get back space for reuse.

Oracle considers the initial memory allocation for the shared pool to be the SGA Heap. This memory architecture iscomprised of heaps and subheaps which are the building blocks of Oracle’s dynamic memory structure.

Since the shared pool is accessible to all server processes, Oracle has mechanisms to synchronize operations and recoverfrom aborted processes. Synchronization and recovery are implemented using latches, state objects, and enqueues.Synchronization is necessary to allow only one user to modify any particular location of memory or read it while anotherprocess is writing. Recovery is necessary when an user process terminates while making a change to an SGA structure.Shared memory recovery is initiated and the memory is freed to be accessible to the shared pool.

Page 12: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-12 ORACLE CONFIDENTIAL , Release 7.3

Section Four: Library Cache ManagerThe library cache manager is a client of the heap manager since it depends on the heap manager to allocate memory neededto store its library cache objects. As the heap manager controls all memory allocations and deallocations, the library cachemanager controls and manages all generic library cache objects, including packages/procedures, cursors, triggers, etc. Thetwo work together to manage and manipulate the shared pool for server process requests.

The library cache manager is designed and implemented to manage a shared library cache but in the single-user user-sideenvironment (e.g. DOS), the same library cache manager can manage a single-user library cache. It also provides recoveryand clean-up of library cache data structures that are abandoned by dead processes by using the client environment’s cleanupprocess to perform the recovery. In a multi-instance environment (i.e. Oracle Parallel Server), the manager will provideconcurrency and consistency control among the multiple SGA’s.

Concepts

The main purpose of the library cache is to provide a mechanism to locate and store any library cache object quickly. Ahashing mechanism is used to locate a handle which contains the identity (name) of the object. The library cache handle thenpoints 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, anonymousPL/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, needsmore memory, it will call the heap manager (KGH) to allocate it. The library cache consists of a hash table which consists ofan array of hash buckets. Each hash bucket is a doubly linked list of library cache object handles. Each library cache objecthandle points to a library cache object and has a reference list. The library cache object is further broken down into othercomponents such as a dependency table, a child table, and an authorization table (to name a few).

Hash Table and Hash Bucket

The hash table is an array of hash buckets. The initial number of the hash buckets is 251; however, the number of bucketswill increase when the number of objects in the table exceeds the next number. The next numbers are the next higher primevalue. They are 251, 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, and 4292967293 where the "n+1"th sizeis approximately twice the "n"th size. The resulting expansion of the hash table will involve allocating a new hash table atthe next prime size, rehashing the library cache objects from the old table to the new table, and freeing the space allocatedfrom the old hash table. Throughout this procedure, access to the hash table is blocked (by freezing access to the childlatches) as one user allocates new buckets to double the size of the hash table and then uses the least significant bits of thehash value to determine which new bucket a handle belongs to. Contrary to common belief, this is a rare and inexpensiveoperation 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, anddatabase link to determine the hash bucket where the object should be found. It then walks down the corresponding linkedlist to see if the object is there. If the object does not exist, the library cache manager will create an empty object with thegiven name, insert it in the hash table, and request the client load it by calling the client's environment-dependent loadfunction. Basically, the client would read from disk, call the heap manager to allocate memory, and load the object.

Note: Resizing a hash table is done automatically and again causes a small hiccup (estimated 3 to 5 seconds) in the system. Expanding thehash table is prompted whenever there are, on average, multiple handles off each bucket. For applications that will reference a largenumber of library cache objects, one can use an undocumented parameter, _kgl_bucket_count, to set the initial number of hash buckets toa higher value to reduce the likelihood of a hash table resize operation. Since the hiccup is small and infrequent and the current valueshould be sufficient, we suggest that most applications should not modify this parameter.

Page 13: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-13

HASH BUCKET

HASH BUCKET

HASH BUCKET

HASH BUCKET

HASH BUCKET

HASH BUCKET

HASH BUCKET

HASH BUCKET

HASH BUCKET

HASH BUCKET

LibraryCacheHandle

L C O

LibraryCachehandle

LibraryCachehandle

LibraryCacheHandle

Hash Bucketlock handlesarray of hash buckets

Dependency Tab le

Chi ld Table

Author izat ion Table

Type

Status Flags

Data Blocks

LCO or l ibrary cacheobject

L IBRARY CACHE

Library Cache Handle

A library cache handle points to a library cache object. It contains the name of the library object, the namespace, atimestamp, a reference list, a list of locks locking the object and a list of pins pinning the object. Each object is uniquelyidentified by the name within its namespace. The library cache manager will generate a name for every object, evenanonymous PL/SQL blocks.

The handle uses namespaces to partition library cache objects by types. These are examples of different types ofnamespaces: 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 itemkept in the library cache. The name consists of the object owner name, the object name, the database link name, and thedatabase 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 todetermine when a handle should be unpinned in memory.

Page 14: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-14 ORACLE CONFIDENTIAL , Release 7.3

Library Cache Object

A library cache object may consist of several parts of which only six elements are discussed: the dependency table, the childtable, the authorization table, the type, the status flags, and the data blocks (containing heaps for storing data). Otherelements exist but are of less importance or significance. The following sections discuss each listed component in detail.

dependency table

child table

authorization table

type

status f lags

data blocks

references to handles of otherl ibrary cache objects

references to chi ld l ibrary cachehand les

privi lege l ist

object type

status f lags

pointers to heap descr iptors thatconta in actual data

L IBRARY CACHEO B J E C T

dependency tableThe dependency table contains references to other library cache objects. For example, a procedure may be dependent onseveral tables. The dependency table will contain pointers to these dependent handles (tables). The relative position of eachreference in the table is important and does not change because it is addressed in the dependent object by its relative positionin the table and not by its name. This dependency information is also stored in a data dictionary table (DEPENDENCY$) orsimply can be viewed in V$OBJECT_DEPENDENCY.

When the library cache manager discovers that the timestamp of an object has changed (during the release of the exclusivepin on the object at commit time or during the re-initialization of the object after it is being purged), it invalidates alldependency references to the object and breaks the locks on it. When the library cache manager discovers that an object haschanged (regardless of whether its timestamp has changed) and that its changes are very likely to be committed successfully,it invalidates all read-only dependents of this object.

child tableThe child table consists of references to child library cache objects (e.g., different versions of a cursor). Each child referencein the hash table is again addressed within the parent object by its relative position in the table since all the children aretextually identical. Child objects or anonymous objects do not have a name in its handle but are referenced via the parentobject which does have a name. In other words, child objects can only be addressed via the parent object. For example, thehash value of a SQL statement is based on the text of the SQL statement itself. If two users issue ‘SELECT * FROM EMP’where the text may match but the EMP table is private to each user, then what one sees is a parent object whose name is theSQL. It will have two children corresponding to the two versions of the SQL that was issued.

Note: A hashing optimization was attempted in 7.1.6 where we only inspected the first and last 64 bytes. However, it was undone whensome applications had many similar SQL statements that hashed to the same value.

Page 15: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-15

Authorization TableThis table contains privileges that have been granted on the library object. Each item in the list consists of an identificationnumber of a user or role, privileges that each user or role has on the object, and optionally an identification number of a partof the object that the privilege is on (e.g. column number of a table).

TypeHere are examples of different library cache object types: shared cursor (SQL cursor or PL/SQL anonymous block), index,table, cluster, view, synonym, sequence, procedure, function, package, table body, package body, and trigger. More will beadded in later versions of Oracle.

Status FlagsThere are a number of status flags combination of which indicate the state of the library cache object. The status flagsindicate the following:1. the object is existent.2. the object is non-existent.3. the object is locally represented.4. the object is being created5. the object is being altered6. the object is being dropped.7. the object is being updated.This will be discussed in more detail in version 2 of the paper.

KGL Data BlocksAt most, there are eight KGL data blocks per object. Each control block contains a heap descriptor which points to a heapof memory which might contain the diana tree, p-code, source code, shared cursor context area, or any other various data.The size of each heap is unlimited. For each data control block, there is a heap pin count. A nonzero heap pin count willdisallow freeing the heap. Each heap is individually pinned and loaded under a library cache object pin. A server processmust pin a heap before reading or modifying its contents. The library cache does not need to know what is actuallycontained within the heaps; thereby heaps are very nice and easy to manage compared to raw data.

Page 16: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-16 ORACLE CONFIDENTIAL , Release 7.3

Library Cache

Object

Data Contro l

B locks

Object Informat ion

0

Source

1

Diana

2

P-Code (Debugg ing)

3

M-Code

4

errors

5

6

7

Object In format ion

0

1

2

3

4

5

SQL P lan

6

7

Library Cache

Object

Data Contro l

B locks

PL /SQLl ibrary cache entry

shared cursorl ibrary cache entry

Heaps or Sub-heaps(do not have to be cont ig ious)

Heaps or Sub-heaps(do not have to be contigious)

L ibrary cache entr ies

From the previous diagram, one can see that a library cache entry can be composed of up to eight heaps or subheaps but it isnot necessary for all eight heaps to be allocated. PL/SQL objects typically use 6 heaps: the common object information heap,source heap, diana heap, p-code heap, m-code heap and the errors heap. The common object information heap contains theglobal name, dependency list, security list and variety of other bookkeeping information about the object. The source heapcontains the PL/SQL source for the compilation unit. The p-code heap was originally intended to store portable executablecode. However, it was never implemented (all code is considered machine dependent), so the p-code heap is primarily usedto store debugging information instead. The m-code heap was intended to contain only machine dependent code, but itactually contains all executable code. The diana contains the parse and syntax trees, description of the meta-data and all itsreferences. Any errors posted during compilation is found in the errors heap.

The Oracle kernel’s SQL processor uses 2 heaps to represent a shared SQL statement: the object information heap andquery/execution plan heap. The name of object also serves as the source for the shared SQL statement. The plan heapcontains the query/execution plan for the SQL statement.

Locking and Pinning

There are 2 types of data structures for concurrency control: locks and pins. A lock has a higher level than a pin. A lock ona handle must be acquired before attempting to pin an object. Locks can be thought of as parse locks while pins can bethought of as short-term locks to read or change the contents of an object. The reason why we have locks and pins insteadof one locking mechanism is to allow as much access to the object as possible.

Both pins and locks will wait until granted; that is, one will wait for a lock or pin to be acquired. If the object is locked orpinned in a conflicting mode, the library cache manager will make the client wait until that the desired lock or pin can begranted..

Page 17: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-17

LocksLocks are only taken on handles.

There are 3 modes for locks: null, share, and exclusive. A null or shared mode is placed on the object when it is onlyintended to be read (e.g. executing an object, referencing the object during compilation). An exclusive lock is needed tomodify the object. There is only a slight difference between a null lock and a shared lock. A null lock on an object can bebroken and usually occurs when another client attempts to pin the same object in exclusive mode. For example, a null lockon a read-only object is broken when there is an exclusive pin on any of the parent objects it depends on. All locks on read-only objects have to be in null mode. On the other hand, an exclusive lock is placed on a library cache object if it is intendedto be written or modified (e.g. compiling or creating a new object or recompiling an existing object). Null locks expressinterest on the handle. They are usually used on cursors when doing a read-only operation. The null lock is invalidatedwhen the cursor is invalidated. This invalidated null lock notifies any process attempting to use this cursor that this objectis invalid.

The persistence of the lock depends on whether it is associated to a session, a transaction, or a call. If it is associated with asession, then it is released when the session closes. If it is associated with a transaction, then the lock will not be releaseduntil the transaction commits or rollback while the lock will released at the completion of the call if it is associated with acall.

Compatibility for lock modes:A is holding a lock on an object (O) of mode:

Client No Lock Null Lock ShareLock

ExclusiveLock

User A is getting another lock of mode NULL Yes Yes Yes YesUser A is getting another lock of mode SHARED Yes Yes Yes YesUser A is getting another lock of mode EXCLUSIVE

Yes Yes No Yes

User B is getting a lock on O of mode NULL Yes Yes Yes YesUser B is getting a lock on O of mode SHARED Yes Yes Yes NoUser B is getting a lock on O of modeEXCLUSIVE

Yes Yes No No

PinsAfter locking a library cache object, a process must then pin the object before accessing it. A process pinning a library cacheobject provides a mask indicating which data blocks (heaps) are to be pinned and loaded. There are two pin modes: sharedand exclusive. A library cache object is pinned in share mode when it is to be read only and in exclusive mode when it is tobe modified.

Pinning/unpinning also helps determine if a heap can be freed. A recreateable chunk (or heap) can be pinned or unpinned.At the time a chunk is allocated, it is pinned by the heap manager. Whenever the client is not actively using the chunk ofspace, he should unpin it. If an allocation request is made and there is not enough space available to satisfy it, the heapmanager can, by invoking a client supplied callback routine, request a client to free an unpinned chunk of space.

ExampleHere is an example of using locks and pins when altering (recompiling) a procedure. First, the library cache object for theprocedure is locked in exclusive mode. This prevents others from performing the same operation or any operation whichwould drop or replace the interested object. Locking also prevents others from creating new procedures, packages, orfunctions that will reference the object. Next, it is pinned in share mode to get to its definition and authorization informationso necessary security and error checking can be performed. Then, the share pin is released, the object is repinned inexclusive mode, and the procedure is recompiled. Finally, all of its dependents have to be invalidated.

Page 18: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-18 ORACLE CONFIDENTIAL , Release 7.3

Library Cache Latches

A latch is a type of lock that can be very quickly acquired and freed. Latches are typically used to prevent more than oneprocess from executing the same piece of code at a given time. Contrast this with locks (enqueues) which are usually usedto prevent more than one process from accessing the same data structure at a given time. Associated with each latch is acleanup procedure that will be called if a process dies while holding the latch. Every latch has an associated level that is usedto prevent deadlocks. Once a process acquires a latch associated with a certain level, it cannot subsequently acquire anotherlatch associated with a equal or lower level (unless it acquires it through a nowait get).

In particular, the library cache latches are required to prevent multiple access to a share library cache entry. Library cachelatches come in three general flavors: the library cache latch, the pin latch and the load-lock latch. The library cache latch isthe latch at the highest level. The library cache latch is needed prior to getting a lock on a handle (e.g., to drop or free thehandle, to invalidate the handle, etc.). A process attempting to pin a heap needs to acquire the library cache pin latch. Toload a library cache entry, the library cache load lock latch is required. This prevents the possibility of multiple processesloading the same object simultaneously. Since there is only one library cache latch (e.g., to walk the linked list of LCOs),one library cache pin latch (e.g., for all library cache objects), and one library cache load latch (e.g., to load new librarycache entries), latch contention must be monitored. Of the three, the library cache latch is used and contended for mostoften. The library cache latch is the most versatile latch since it is acquired prior to hashing to a handle, dropping a handle,and creating a new handle.

Oracle soon realised that these latches could be enormous bottlenecks as the level of concurrent activity in the systemincreases. In Oracle 7.2, we have multiple library cache latches to help alleviate this problem. Each latch will be designatedto several specific hash values. In this model, the library cache hash table will be broken into ranges. A handle which hashesinto bucket M will be protected by latch id# (M mod N), where the latch ids are 0,1, ..., N-1. This means that there will be alist of free lock descriptors, pin descriptors, handles, heap descriptors, etc. for each latch. This will allow users to performmost operations through KGL (like locking, pinning, invalidation, etc.) using the one latch that is required for the handle ofthe object being operated on. (More information can be found in Amit Jasuja’s Multiple Latches in KGL paper).

Page 19: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-19

Section Five: Tuning and Monitoring the Shared Pool

INTRODUCTION

As described in the previous sections, every object and shareable segment is found in the shared pool. The shared pool islimited by the size of the available heap memory and efficient use of this memory will be dependent on application designand the activity occurring in the database. This section focuses on application design and the effects of this on the sharedpool. Its main emphasis is on describing ways to tune and monitor the shared pool.

Shared pool tuning is much different from other areas of database tuning where there are many init.ora parameters that onecan tweak and adjust. Other than increasing and decreasing the shared pool size, most tuning concepts will center aroundunderstanding the application and then using that knowledge to keep important packages in the shared pool, set or unsetcursor_space_for_time, or set session_cache_cursors to a relevant value. One or a combination of these operations hopefullywill result in reduced misses in the library cache and in reduced fragmentation. For the most part, application codingstandards and techniques are required to optimally tune the shared pool and efficiently use the sharing mechanisms of thelibrary cache. A bad application will potentially render other tuning options futile.

QUICK TUNING TIPS

First, we should take a high level approach to simply diagnose the existing performance. We need to determine if the currentperformance is acceptable and what resources are available to improve the performance. It is common that increasing sharedpool size will be needed; hopefully, sufficient memory is available to prevent paging and swapping of the SGA.

One can quickly discover if there is a performance problem in the library cache by monitoring the cache hit ratios. A cachemiss in the library cache or dictionary cache is potentially more expensive than a miss in the buffer cache. For this reason,one must allocate sufficient memory for the shared pool first. Furthermore, the algorithm that Oracle uses to manage data inthe shared pool tends to hold dictionary data in memory longer than library cache data. Thus, tuning the library cache to anacceptable cache hit ratio often ensures that the data dictionary cache hit ratio is also acceptable.

Tuning the library cache

DescriptionA library cache miss can occur during the parse or execute phase.

Parse: If an application makes a parse call for a SQL statement and the parsed representation of the statement does not existin a shared SQL area in the library cache, Oracle parses and allocates space in the shared SQL area. You can reduce librarycache misses by ensuring that SQL statements can share a shared SQL area whenever possible.

Execute: If an application makes an execute call for a SQL statement and the shared SQL area containing the parsedrepresentation of the statement has been deallocated from the library cache to make room for another statement, Oracleimplicitly reparses the statement, allocates a new shared SQL area for it and executes it. You may be able to reduce thelibrary cache misses on execution calls by allocating more memory to the library cache.

Page 20: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-20 ORACLE CONFIDENTIAL , Release 7.3

DiagnosisV$LIBRARYCACHE view will be used to determined if there is a performance problem within the library cache. Thenamespace describes the type of an item kept in the library cache.

The following query outlines the ratio of cache handles and cache objects to be pinned for each namespace. It also gives anidea of what type of activity is occurring in the library cache.

select namespace, gets, gethitratio, pins, pinhitratio, reloads, invalidations from v$librarycache;

NAMESPACE GETS GETHITRATIO PINS PINHITRATIO RELOADS INVALIDATIONSSQL AREA 36633 .991019027 15790 .91436865 1487 29TABLE/PROCEDURE 5984 .816086957 8941 .828913043 206 0BODY 155 .941034344 155 .941034344 0 0TRIGGER 1 1 1 1 0 0INDEX 28 .107142857 29 .103988422 1 0CLUSTER 27 .444444444 15 .333333333 0 0OBJECT 0 1 0 1 0 0PIPE 0 1 0 1 0 0

When there is large numbers of gets and pins (over 1000) and the gethitratio and pinhitratio is low (less than 85%), theshared pool size needs to be increased or other tuning techniques discussed in this paper needs to be investigated. Reloadsindicate that library objects have to be reinitialized and reloaded with data because they have been aged out or invalidated.Total reloads should be near 0. If the ratio of RELOADS to PINS is more than 1%, then you should reduce the library cachemisses. High invalidations indicate that non-persistent library objects (like shared SQL areas) have been invalidatedprobably due to role changes or altering tables. Development may be occurring which changes or recreate tables andprivileges which may cause unnecessary invalidations. A closer look of the application may be required.

However, it is very difficult to tune one particular namespace. For that reason, this query is normally used to give an idea oftotal misses and access attempts in the library cache. The sum(pins) indicates the number of times that SQL statements,PL/SQL blocks and object definitions were accessed for execution. The sum(reloads) indicates the number of times thoseexecutions resulted in library cache misses causing Oracle to implicitly reparse a statement or block or reload an objectdefinition because it has been aged out.

select sum(pins) "executions" , sum(reloads) "cache misses while executing" from v$librarycache;

executions cache misses while executing---------- ---------------------------- 1625 7

V$ROWCACHE view gives statistics for data dictionary activity. Each row contain statistics for one data dictionary cache.In version 6, Oracle gives the capability of tuning each parameter. In Oracle7 and higher, the dictionary cache which is partof the row cache grabs memory from the Generic Heap. When required, the row cache will grow to accomodate more datadictionary entries if space is available. The following queries will indicate if there are data dictionary cache misses.

select parameter, gets/(gets+getmisses) “hit ratio” from v$rowcache;orselect sum(gets)/(sum(gets)+sum(getmisses)) “total hit ratio” from v$rowcache;

Action

One can reduce library cache misses by (1) allocating additional memory for the library cache or (2) writing identical SQLstatements or shareable code. Increasing shareable memory is as simple as increasing the size of the shared_pool_size. One

Page 21: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-21

must be careful not to induce paging or swapping due to insufficient memory. In order for different occurrences of a SQLstatement or PL/SQL block to share a shared SQL area, they must have identical text including space and case, reference thesame schema objects, bind variables must match in name and data type and use the same optimizer approach. This will bediscussed further later in this section.

If the total hit ratio is high in the row cache, then one should monitor the amount of memory allocated in the ‘dictionarycache’ and ‘free memory’ via V$SGASTAT. If the ‘dictionary cache’ is relatively unchanging (not growing throughout theday) and ‘free memory’ is large and also showing little fluctuations (greater than dictionary cache), then the bad hit ratio maybe caused by users dropping and recreating objects or modifying grants. This should be reflected by hit ratios on subordinaterow cache types found in V$ROWCACHE. If there is very low free memory and the overall hit ratio is below 90% , thenincreasing the shared pool should help tune the row cache.

(bug 294270 for more information)

MEMORY FRAGMENTATION

The primary problem that occurs is that free memory in the shared pool becomes fragmented into small pieces over time.Any attempt to allocate a large piece of memory in the shared pool will cause large amount of objects in the library cache tobe flushed out and may result in an ORA-4031 out of shared memory error. (information from Juan Luanza’s shared pooltuning paper)

DIAGNOSIS

i) ORA-4031 ERROR

One way to diagnose that this is happening is to look for ORA-4031 errors being returned from applications. When anattempt is made to allocate a large contiguous piece of shared memory, and not enough contiguous memory can be created inthe shared pool, the database will signal this error.

Before this error is signaled, all objects in the shared pool that are not currently pinned or in use will be flushed from theshared pool, and their memory will be freed and merged. This error only occurs when there is still not a large enoughcontiguous piece of free memory after this happens. There may be very large amounts of total free memory in the sharedpool, but just not enough contiguous memory.

Note: From 7.0.15, the compiled code for a package was split into more than one piece, each piece being only about 12K insize. So, the 64K restriction was lifted; however, packages larger 100K still may have problems compiling. Furthermore,with releases 7.2/2.3 of Oracle7/PLSQL, loading a library unit (package, function, procedure) into the shared pool does NOTrequire one contiguous piece of memory in the shared pool. This means that chances of getting ORA-4031 is dramaticallyreduced.

ii) INIT.ORA PARAMETER

An init.ora parameter can be set so that whenever an ORA-4031 error is signaled a dump will occur into a trace file. Bylooking for these trace files, the DBA can determine that these errors are occurring. This is useful when applications do notalways report errors signaled by oracle, or if users do not report the errors to the DBAs. The parameter is the following:

event = "4031 trace name errorstack"

Page 22: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-22 ORACLE CONFIDENTIAL , Release 7.3

If you are using 7.0.16 or higher you can use the following:

event = "4031 trace name errorstack, level 4"

This will cause a dump of the oracle state objects to occur when this error is signaled. By looking in the dump for'load=X' and then looking up a few lines for 'name=' you can often tell whether an object was being loaded into the sharedpool when this error occurred. If an object was being loaded then it is likely that this load is the cause of the problem and theobject should be 'kept' in the shared pool. The object being loaded is the object printed after the 'name='. Do not use the'level 4' option in versions before 7.0.16 because a bug existed that often caused the system to crash with this option enableddue to a latch level violation.

iii) X$KSMLRU

There is a fixed table called X$KSMLRU that tracks allocations in the shared pool that cause other objects in the sharedpool to be aged out. This fixed table can be used to identify what is causing the large allocation. The columns of thisfixed table are the following:

KSMLRCOM - allocation comment that describes the type of allocation.

If this comment is something like 'MPCODE' or 'PLSQL%' then there is a large PL/SQL object being loaded into theshared pool. This PL/SQL object will need to be 'kept' in the shared pool.

If this comment is 'kgltbtab' then the allocation is for a dependency table in the library cache. This is only a problem whenseveral hundred users are logged on using distinct user ids. The solution in this case is to use fully qualified names for alltable references. This problem will not occur in 7.1.3 or later.

If you are running MTS and the comment is something like 'Fixed UGA' then the problem is that the init.ora parameter'open_cursors' is set too high.

KSMLRSIZ - amount of contiguous memory being allocated. Values over around 5K start to be a problem, values over 10Kare a serious problem, and values over 20K are very serious problems. Anything less then 5K should not be a problem.

KSMLRNUM - number of objects that were flushed from the shared pool in order allocate the memory.

In release 7.1.3 or later, the following columns also exist:

KSMLRHON - the name of the object being loaded into the shared pool if the object is a PL/SQL object or a cursor.

KSMLROHV - hash value of object being loaded

KSMLRSES - SADDR of the session that loaded the object.

The advantage of X$KSMLRU is that it allows you to identify problems with fragmentation that are effecting performance,but that are not bad enough to be causing ORA-4031 errors to be signaled. If a lot of objects are being periodically flushedfrom the shared pool then this will cause response time problems and will likely cause library cache latch contentionproblems when the objects are reloaded into the shared pool.

One unusual thing about the X$KSMLRU fixed table is that the contents of the fixed table are erased whenever someoneselects from the fixed table. This is done since the fixed table stores only the largest allocations that have occurred. Thevalues are reset after being selected so that subsequent large allocations can be noted even if they were not quite as large asothers that occurred previously. Because of this resetting, the output of selecting from this table should be carefully notedsince it cannot be reselected if it is forgotten. Also you should take care that there are not multiple people on one databasethat select from this table because only one of them will select the real data.

Page 23: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-23

To monitor this fixed table just run the following:

select * from X$KSMLRU where KSMLRSIZ > 5000;

ACTION

i) KEEPING OBJECTS

The primary source of problems is large PL/SQL objects. The means of correcting these errors is to 'keep” large PL/SQLobjects in the shared pool at startup time. This will load the objects into the shared pool and will make sure that the objectsare never aged out of the shared pool. If the objects are never aged out then there will not be a problem with trying to loadthem and not having enough memory.

Objects are 'kept' in the shared pool using the dbms_shared_pool package that is defined in the dbmspool.sql file. Forexample:

execute dbms_shared_pool.keep('SYS.STANDARD');

All large packages that are shipped should be 'kept' if the customer uses PL/SQL. This includes 'STANDARD','DBMS_STANDARD', and 'DIUTIL'.

All large customer packages should also be marked 'kept'.

One restriction on the 'keep' procedure is that it only works on packages. If the customer has large procedures or largeanonymous blocks, then these will need to be put into packages and marked kept.

You can determine what large stored objects are in the shared pool by selecting from the V$DB_OBJECT_CACHE fixedview. This will also tell you which objects have been marked kept. This can be done with the following query:

select * from V$DB_OBJECT_CACHE where sharable_mem > 10000;

Note that this query will not catch PL/SQL objects that are only rarely used and therefore the PL/SQL object is not currentlyloaded in the shared pool.

To determine what large PL/SQL objects are currently loaded in the shared pool and are not marked 'kept' and therefore maycause a problem, execute the following:

select name, sharable_mem from V$DB_OBJECT_CACHE where sharable_mem > 10000 and (type = 'PACKAGE' or type = 'PACKAGE BODY' or type = 'FUNCTION' or type = 'PROCEDURE') and kept = 'NO';

Note: Oracle 7.1.6 and on, bugs 192829 and 205976 have been fixed. Now you can pin procedures and triggers with thedbms_shared_pool procedure. Either procedures or packages can be pinned with the ‘P’ flag, which is the default value.Triggers are pinned with ‘R’ and anonymous PL/SQL blocks need any letter other than [p,P,r,R] as a flag.

Page 24: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-24 ORACLE CONFIDENTIAL , Release 7.3

ii) USE BIND VARIABLES

Another thing that can be done to reduce the amount of fragmentation is to reduce or eliminate the number of SQLstatements in the shared pool that are duplicates of each other except for a constant that is embedded in the statement. Thestatements should be replaced with one statement that uses a bind variable instead of a constant.

For example: select * from emp where empno=1; select * from emp where empno=2; select * from emp where empno=3;Should all be replaced with: select * from emp where empno=:1;

You can identify statements that potentially fall into this class with a query like the following:

select substr(sql_text, 1, 30) sql, count(*) copies from v$sqlarea group by substr(sql_text, 1, 30) having count(*) > 3;

iii) MAX BIND SIZE

It is possible for a sql statement to not be shared because the max bind variable lengths of the bind variables in the statementdo not match. This is automatically taken care of for precompiler programs and forms programs, but could be a problem forprograms that directly use OCI. The bind call in OCI takes two arguments, one is the max length of the value, and the otheris a pointer to the actual length. If the current length is always passed in as the max length instead of the max possiblelength for the variable, then this could cause the sql statement not to be shared.

To identify statements that might potentially have this problem execute the following statement:

select sql_text, version_count from v$sqlarea where version_count > 5;

iv) ELIMINATING LARGE ANONYMOUS PL/SQL

Large anonymous PL/SQL blocks should be turned into small anonymous PL/SQL blocks that call packaged functions. Thepackages should be 'kept' in memory. This includes anonymous PL/SQL blocks that are used for trigger definitions. Largeanonymous blocks can be identified with the following query:

select sql_text from v$sqlarea where command_type=47 -- command type for anonymous block and length(sql_text) > 500;

Note that this query will not catch PL/SQL blocks that are only rarely used and therefore the PL/SQL block is not currentlyloaded in the shared pool.

Page 25: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-25

Another option that can be used when an anonymous block cannot be turned into a package is to mark the anonymous blockwith some string so that it can be identified in v$sqlarea and marked 'kept'.

For example, instead of using

declare x number; begin x := 5; end;

one can use: declare /* KEEP_ME */ x number; begin x := 5; end;

You can then use the following procedure to select these statements out of the shared pool and mark them 'kept' using thedbms_shared_pool.keep package.

declare /* DONT_KEEP_ME */ addr varchar2(10); hash number; cursor anon is select address, hash_value from v$sqlarea where command_type = 47 -- command type for anonymous block and sql_text like '% KEEP_ME %' and sql_text not like '%DONT_KEEP_ME%';

begin open anon;

loop fetch anon into addr, hash; exit when anon%notfound; dbms_shared_pool.keep(addr || ',' || to_char(hash), 'C'); end loop;

end;

Page 26: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-26 ORACLE CONFIDENTIAL , Release 7.3

LIBRARY CACHE LATCH CONTENTION

Another big problem that can occur in Oracle7 on multiprocessors that have a large number of CPUs is contention for thelibrary cache latch.

DIAGNOSIS

i) V$LATCH

Selecting from V$LATCH will show you which latches have the worst hit rates and more importantly which latches arecausing alot of sleeps. If the library cache latch is causing the most number of sleeps then you may have a problem. Onething to watch out for here is that this information is accumulated since the database starts, and so it may not show problemsthat are intermittent in nature.

ii) V$SESSION_WAIT

By selecting from V$SESSION_WAIT during a slowdown period you can usually determine very accurately whether youhave a problem with latching and which latch is causing the problem. If you see a large number (more then 3 or 4) ofprocesses waiting for the library cache or library cache pin latch, thenthere may be a problem. Run the following query to determine this:

select count(*) number_of_waiters from v$session_wait w, v$latch l where w.wait_time = 0 and w.event = 'latch free' and w.p2 = l.latch# and l.name like 'library%';

It is also very useful to just select from v$session_wait to determine what else is causing a slowdown:

select * from v$session_wait where event != 'client message' and event not like '%NET%' and wait_time = 0 and sid > 5;

CORRECTION

i) FRAGMENTATION

The primary cause of library cache latch contention is fragmentation of the shared pool. This can be diagnosed andaddressed as described in the fragmentation section of this document. If you are running on a system with just one or a verysmall number of CPUs and you have a problem with library cache latch contention, then fragmentation is almost certainlythe source of the problem.

ii) INCREASE SHARING

By increasing the amount of sharing that occurs on the system you can decrease the amount of missing and loading thatoccurs in the library cache and therefore the load on the library cache latch. This is done by identifying statements that arenot being shared as described in the fragmentation section above.

Page 27: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-27

To determine the percentage of sql statement parse calls that find a cursor to share you can execute the following:

select gethitratio from v$librarycache where namespace = 'SQL AREA';

This value should be in the high nineties.

iii) REDUCE PARSING

Another way to decrease the load on the library cache latch is to reduce the number of parse calls that are coming into thesystem. Even if the statement being parsed is found in the shared pool and shared, the load of a parse call is high becausethe user must be authenticated to run the sql statement, and all name translations must be done for the SQL statement.Reducing the amount of parsing is often as simple as setting 'HOLD_CURSOR=TRUE' for the precompilers. To identify thesql statements that are receiving a lot of parse calls execute the following:

select sql_text, parse_calls, executions from v$sqlarea where parse_calls > 100 and executions < 2*parse_calls;

To identify the total amount of parsing going on in the system execute the following:

select name, value from v$sysstat where name = 'parse count';

If this value increases at a rate greater than about 10 per second then this may be a problem.

iv) CURSOR_SPACE_FOR_TIME

Setting the init.ora parameter CURSOR_SPACE_FOR_TIME to TRUE can reduce the load on the library cache latchsomewhat. However, setting this parameter may add a lot of memory utilization, so before setting it to true make sure thatthere is a lot of free memory on the system and that the number of hard page faults per minute is very low or zero.

v) SESSION_CACHED_CURSORS

In version 7.1 there is an init.ora parameter called SESSION_CACHED_CURSORS that can be set that will help insituations where a user repeatedly parses the same statements. This can occur in many applications including FORMS basedapplication if users often switch between forms. Every time a user switches to a new form all the sql statements opened forthe old form will be closed. The SESSION_CACHED_CURSORS parameter will cause closed cursors to be cached withinthe session so that a subsequent call to parse the statement will bypass the parse phase. This is similar to HOLD_CURSORSin the precompilers. One thing to be careful about is that if this parameter is set to a high value, the amount of fragmentationin the shared pool may be increased.

vi) USING FULLY QUALIFIED TABLE NAMES

It can help to reduce the load on the library cache latch somewhat to use fully qualified names for tables in sql statements.That is, instead of saying 'select * from emp', say 'select * from scott.emp'. This is especially helpful for sql statements thatare parsed very frequently. If all users log into the database using the same userid then this may be of little or no use.

vii) FORMS 4

SQL*forms version 4 generates less dynamic sql by making better use of bind variables. Therefore, less loading occurs inthe shared pool. One might consider switching to this new version sooner than you otherwise would have because ofthis.

Page 28: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-28 ORACLE CONFIDENTIAL , Release 7.3

SIZING OF SHARED POOL

One very difficult judgment that needs to be make in Oracle7 is to determine the proper size of the shared pool. Thefollowing provides some guidelines for this. It should be emphasized that these are just guidelines, there are no hard and fastrules here and experimentation will be needed to determine a good value.

The shared pool size is highly application dependent. To determine the shared pool size that will be needed for aproduction system it is generally necessary to first develop the application and run it on a test system and take somemeasurements. The test system should be run with a very large value for the shared pool size to make the measurementsmeaningful.

OBJECTS STORED IN THE DATABASE

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

select sum(sharable_mem) from V$DB_OBJECT_CACHE;

This is especially effective because all large pl/sql object should be 'kept' in the shared pool at all times.

SQL

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

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 ofmemory will be needed for the shared sql plus more for the dynamic sql. Sufficient memory should be allocated so that thedynamic sql does not age the shared sql out of the shared pool.

The amount of memory for the shared sql can be approximated by the following:

select sum(sharable_mem) from v$sqlarea where executions > 5;

The remaining memory in v$sqlarea is for dynamic sql. Some shared pool will need to be budgeted for this also, but thereare few rules here.

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 userhas whether the cursor is shared or not. During the peak usage time of the production system, you can measure this asfollows:

select sum(250 * users_opening) from v$sqlarea;

Page 29: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-29

In a test system you can measure it by selecting the number of open cursors for a test user and multiplying by the totalnumber of 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 = 23; -- replace 23 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.

MTS

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

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:

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:

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';

OVERHEAD

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

Estimating Procedure

This will help estimate how big the shared pool should be at this moment

set serveroutput on;

declare

Page 30: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-30 ORACLE CONFIDENTIAL , Release 7.3

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 usedselect sum(sharable_mem) into shared_sql from v$sqlarea;

-- User Cursor Usage -- run this during peak usageselect 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 resultsdbms_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 pool utilization (total): '|| to_char(used_pool_size) || ' bytes ' || '(' ||to_char(round(used_pool_size/1024/1024,2)) || 'M)');

Page 31: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-31

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;/

COMMON FALLACIES

There are a number of common fallacies about the shared pool that are often stated as fact.

FREE MEMORY

One fallacy is that the amount of 'free memory' reported in v$sgastat needs to be kept high. This is incorrect. The freememory reported in this table is not like the free memory reported by operating system statistics. Since the shared pool actsas a cache, nothing will ever be aged out of the shared pool until all the free memory has been used up. This is entirelynormal.

Free memory is more properly thought of as 'wasted memory'. You would rather see this value be low than very high. Infact, a high value of free memory is sometimes a symptom that a lot of objects have been aged out of the shared pool andtherefore the system is experiencing fragmentation problems.

FLUSH SHARED POOL

Some people think that frequently executing 'alter system flush shared_pool' improves the performance of the system anddecreases the amount of fragmentation. This is incorrect. Executing this statement causes a big spike in performance anddoes nothing to improve fragmentation. Flushing the shared pool does not flush “pinned” or “kept” objects.

The only time when it might be useful to run this statement is between shifts of users so that the objects that are relevant tothe last shift of users can be flushed out before the next shift of users starts to use the system. This is almost never neededthough. However, I have seen bugs where flushing the shared pool did fix some locking contentions.

Page 32: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-32 ORACLE CONFIDENTIAL , Release 7.3

SUMMARY

The most important point that needs to be understood by everyone using Oracle7 and PL/SQL is that all large PL/SQLobjects must be made into packages and those packages must be kept in the shared pool. This point cannot be overemphasized. Many customers, especially those running a lot of users, have had terrible performance problems that werecompletely cleared up by doing this.

MONITORING AND V$VIEWS

This sections outlines some of the key views utilized to monitor the shared pool and the library cache. Oracle 7 ReferenceGuide and Oracle 7 DBA guide has complete descriptions of all the columns.

V$DB_OBJECT_CACHEShows database objects that are cached in the library cache. Objects include tables, indexes, clusters, synonyms definitions,PL/SQL procedures and packages, and triggers. Objects with large sharable memory (over 5K) should be kept if possible.Large loads values (over 5) may be reduced if the object (table, package, or sequence) can be cached or kept in the sharedpool.

V$LIBRARYCACHEStatistics on the library cache management.The get hit ratio, pin hit ratio, reloads and invalidations should be monitored throughout time. If the hit ratios drop, one canfirst determine if the application or load on the database has changed recently. In particular, SQL AREA namespace shouldhave a high hit ratio. Low hit ratio may be mitigated by writing sharable code.

V$OBJECT_DEPENDENCYDynamic performance table that can be used to determine what objects are depended on by a package, procedure, or cursorthat is currently loaded in the shared pool.

This query describes the owner and name of objects that the application depends on when given the cursor text.

column dependent_owner format a10column dependent_name format a15

select to_owner dependent_owner, to_name dependent_namefrom v$object_dependency d, v$sql s wheres.address=.d.from_address and s.hash_value=d.from_hash and s.sql_text like ‘%cursor text%’and to_owner!=‘SYS’;

This query describes the owner and name of objects that the application depends on when given the sid. This only evaluatesthe current statement.

select s.sql_text to_owner dependent_owner, to_name dependent_namefrom v$object_dependency d, v$sql s , v$session ses whered.from_address=s.address and d.from_hash=s.hash_value and ses.sid=&SID andses.sql_address= s.address and ses.sql_hash_value= s.hash_value and to_owner!=‘SYS’ ;

V$SGASTATIt has detailed information on the System Global Area and its fixed and varied allocations of memory. One should monitorthe difference (deltas) between the value of bytes per component of the SGA. This should be used for capacity planning and

Page 33: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-33

describes what activity is eating up most of the space in the SGA. In particular, pay close attention to the amount of ‘freememory’, ‘library cache’, ‘sql area’, and ‘dictionary cache’. Ideally, ‘free memory’ should be low (< 1 MB) while ‘librarycache’, ‘sql area’, and ‘dictionary cache’ should be stable with high hit ratios from v$librarycache and v$rowcache.

select name, bytes from v$sgastat;

V$SQLAREAIt contains statistics on the shared cursor cache. Each row has statistics on one shared cursor.It has the most versatile purposes. V$SQLAREA can be used to find the number of open cursors (countingUSERS_OPENING), locate common potentially sharable code (using SQL_TEXT), locate cursors with many versions(using VERSION_COUNT), cursors or anonymous blocks that should be called via packages (looking for largeSHARABLE_MEM) and the number reads and writes completed by this cursor. Here are a list of some of the queries thatone may want to run. Some are repeats from discussions above.

Locates almost identical written code that are not shared usually because bind variables are not used.

select substr(sql_text, 1, 30) sql, count(*) copies from v$sqlarea group by substr(sql_text, 1, 30) having count(*) > 3;

Identifies cursors that have identical sql text but are not shared because of differences in definition or declaration. WithOCI, max bind size may vary which will cause the cursor not to be shared.

select sql_text, version_count from v$sqlarea where version_count > 5;

Large anonymous PL/SQL blocks should be turned into small anonymous PL/SQL blocks that call packaged functions. Thepackages should be 'kept' in memory. This includes anonymous PL/SQL blocks that are used for trigger definitions. Largeanonymous blocks can be identified with the following query:

select sql_text from v$sqlarea where command_type=47 -- command type for anonymous block and length(sql_text) > 500;

These queries track and measure the amount sharable memory used for sql and estimates for dynamic sql.

select sum(sharable_mem) from v$sqlarea;

Or to estimate space for dynamic sql.

select sum(sharable_mem) from v$sqlarea where executions > 5;

Identifies cursors with high number of parse calls.

select sql_text, parse_calls, executions from v$sqlarea where parse_calls > 100 and executions < 2*parse_calls;

Page 34: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-34 ORACLE CONFIDENTIAL , Release 7.3

To measure the memory utilized and I/O from a particular cursor.

select sql_text, sharable_mem, persistent_mem, runtime_mem, sorts, parse_calls, disk_reads,buffer_gets, rows_processed where sql_text like ‘%cursor text%’ or parser_schema_id=‘&Name’;

Note: To only measure open cursors then add this to the where clause, ‘and users_opening>0’.

what are all the command types?

V$SQLThis table is identical to V$SQLAREA except that it does not join all SQL statements with the same text together. Theremay be multiple rows in this table with the same SQL statement if there are multiple versions of the cursor in the cursorcache. Version count is not found in V$SQL because each SQL will have its own row.

V$OPEN_CURSORCursors that each user session currently has opened and parsed.

To identify how many open cursors are on the system.

select count(*) from v$open_cursors;

To identify which cursors are opened by a particular user?

select sql_text, hash_value, address from v$open_cursor where user_name = ‘&USER_NAME’;

V$ROWCACHEStatistics for data dictionary activity. Each row contain statistics for one data dictionary cache.

To measure the rowcache hit ratio.

select parameter, gets/(gets+getmisses) “hit ratio” from v$rowcache;orselect sum(gets)/(sum(gets)+sum(getmisses)) “total hit ratio” from v$rowcache;

V$SESSION_CURSOR_CACHEDisplays information on cursor usage for the current session. This is very helpful in determining the maximum number ofcursors allowed opened at one time, current number cursors in use, cursor open information, and the hit ratio. If memorypermits and hit ratio is low, then one should consider increasing session_cached_cursors.

select maximum, count, opened_once, open, opens, hits, hit_ratio from v$session_cursor_cache;

V$SYSTEM_CURSOR_CACHEDisplays similar information to the V$SESSION_CURSOR_CACHE view except that this information is system wide.

select opens, hits, hit_ratio from v$system_cursor_cache;

Page 35: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-35

V$SYSSTATThe current system wide value for each statistic. The following parameters should be monitor and measured throughouttime. The following is a list of important parameters.

1. open cursors current == how many cursors open currently. Should be ran during busy peaks of the applicationcycle.

2. open cursors cumulative == total number of cursors opened since database open. Used with bstat/estat tomeasure number of cursors between time interval.

3. cursor authentications == ## times that cursor privileges have been verified , either for select or becauseprivileges were revoked from an object , causing all users of the cursors to be reauthenticated.

4. session uga memory == total number of session uga memory (good estimate if thinking about implementingMTS)

5. session uga memory max == maximum size of the uga6. session pga memory == total pga memory allocated7. session pga memory max == maximum pga memory allocated8. parse count should not increase more than 10 per second.9. session cursor cache count == count of session cursors cached.10. session cursor cache hits == used with session cursor cache count to find the total hit ratio.

SCRIPTS AND INIT.ORA PARAMETERS

Bstat/Estat for Shared Pool.(modified Vinay Shrihari’s bstat/estat format)README.txtThese are a collection of shared pool scripts to monitor ,among other things, system statistics, library cache,dictionary cache,latches, and system events. These scripts are a modification of the current bstat/estat and the comp_ratios.sql script thatVinay Srihari wrote. The main difference is that data from begin stats, from end stats and from summary data are stored inhistory tables; so, statistics can be compared throughout time and for capacity planning.

1. drop.sql --- drops all tables, sequence and procedures.2. pool_obj.sql- creates all tables, sequences and procedures.3. p_bstat --- inserts statistics into begin stats tables.4. p_estat --- inserts statistics into end stats tables and history tables5. p_query.sql - Queries the most recent bstat/estat statistics and spools into6. a file.7. comp_ratios.sql--- Called by ESTAT script to generate8. * key ratios for analysis.9. * Should not be run separately.

Shared pool tuning usually involves monitoring throughout a complete application cycle instead of a subset of the cycle.

drop.sqlThis scripts allows the user to quickly drop all objects involved in the shared pool scripts.

drop sequence stat$interval;drop table stats$begin_stats ;drop table stats$end_stats ;drop table stats$begin_latch ;drop table stats$end_latch ;

Page 36: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-36 ORACLE CONFIDENTIAL , Release 7.3

drop table stats$begin_lib ;drop table stats$end_lib ;drop table stats$begin_dc ;drop table stats$end_dc ;drop table stats$begin_event ;drop table stats$end_event ;drop table stats$dates ;drop table hist$dates ;drop table hist$stats ;drop table hist$latches ;drop table hist$event ;drop table hist$dc ;drop table hist$lib ;drop table hist$ratios;drop procedure estat;

pool_obj.sql

This script creates objects for shared pool bstat/estat. The sequence number is the unique key that will be joined to get allinformation for specific run. It is therefore the unique identifier for a particular run of BSTAT/ESTAT.

create sequence stat$interval increment by 1 start with 1;

/* begin and end stats */create table stats$begin_stats as select 1 test, v$sysstat.*from v$sysstat where 0=1;

create table stats$end_stats as select * from stats$begin_stats;

create table stats$begin_latch as select 1 test, v$latch.*from v$latch where 0 = 1;

create table stats$end_latch as select * from stats$begin_latch;

create table stats$begin_lib as select 1 test,v$librarycache.*from v$librarycache where 0 = 1;

create table stats$end_lib as select * from stats$begin_lib;

create table stats$begin_dc as select 1 test,v$rowcache.*from v$rowcache where 0 = 1;

create table stats$end_dc as select * from stats$begin_dc;

create table stats$begin_event as select 1 test,v$system_event.*from v$system_event where 0 = 1;

create table stats$end_event as select * from stats$begin_event;

create table stats$dates (test number,type varchar2(10), stats_gather_times varchar2(100));

Page 37: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-37

/* summary stats */create table hist$dates (test number,type varchar2(10), stats_gather_times varchar2(100));

create table hist$stats asselect 1 test, e.value-b.value change , b.name from stats$begin_stats b , stats$end_stats e where 1=2;

create table hist$latches asselect 1 test, e.gets-b.gets gets, e.misses-b.misses misses, e.sleeps-b.sleeps sleeps, e.immediate_gets-b.immediate_gets immed_gets, e.immediate_misses-b.immediate_misses immed_miss, e.name from stats$begin_latch b , stats$end_latch e where 1=2;

create table hist$event as select 1 test, e.total_waits-b.total_waits event_count, e.time_waited-b.time_waited time_waited, e.event event from stats$begin_event b , stats$end_event e where 1=2 union select 1 test, e.total_waits event_count, e.time_waited time_waited, e.event event from stats$end_event e where 1=2;

create table hist$dc asselect 1 test, b.parameter name, e.gets-b.gets get_reqs, e.getmisses-b.getmisses get_miss, e.scans-b.scans scan_reqs, e.scanmisses-b.scanmisses scan_miss, e.modifications-b.modifications mod_reqs, e.count count, e.usage cur_usage, e.fixed fixed from stats$begin_dc b, stats$end_dc e where 1=2;

create table hist$lib asselect 1 test, e.namespace, e.gets-b.gets gets, e.gethits-b.gethits gethits, e.pins-b.pins pins, e.pinhits-b.pinhits pinhits,

Page 38: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-38 ORACLE CONFIDENTIAL , Release 7.3

e.reloads - b.reloads reloads, e.invalidations - b.invalidations invals from stats$begin_lib b, stats$end_lib e where 1=2;

/* comparison of ratios */create table hist$ratios (test number, Name varchar2(40), Value number, Ratio varchar2(30));

/* create end statistics procedure which inserts into end tables and into history and summary tables */

create or replace procedure estat iscounter number;

begin-- get the last sequence generated from bstat

select max(test) into counter from sys.stats$begin_latch;-- insert into end stats tables

insert into stats$end_event select counter, v$system_event.*from v$system_event;insert into stats$end_latch select counter,v$latch.*from v$latch;insert into stats$end_stats select counter, v$sysstat.*from v$sysstat;insert into stats$end_dc select counter, v$rowcache.*from v$rowcache;insert into stats$end_lib select counter, v$librarycache.*from v$librarycache;insert into hist$dates

select counter, 'End', to_char(sysdate, 'dd-MON-yy hh24:mi:ss') from dual;-- insert into history tables

insert into hist$statsselect counter, e.value-b.value change , b.name

from stats$begin_stats b , stats$end_stats e where e.statistic# = b.statistic#

and b.test= counter and e.test=counter;insert into hist$latchesselect counter, e.gets-b.gets gets,e.misses-b.misses misses,e.sleeps-b.sleeps sleeps,e.immediate_gets-b.immediate_gets immed_gets,e.immediate_misses-b.immediate_misses immed_miss,e.name

from stats$begin_latch b , stats$end_latch ewhere e.latch# = b.latch#and b.test=counter and e.test=counter;insert into hist$event

select counter, e.total_waits-b.total_waits event_count, e.time_waited-b.time_waited time_waited, e.event event from stats$begin_event b , stats$end_event e where b.event = e.event and b.test=counter and e.test=counter union select counter, e.total_waits event_count,

Page 39: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-39

e.time_waited time_waited, e.event event from stats$end_event e where e.event not in ( select b.event from stats$begin_event b

where b.test=counter) and e.test=counter;

insert into hist$dcselect counter, b.parameter name,

e.gets-b.gets get_reqs, e.getmisses-b.getmisses get_miss, e.scans-b.scans scan_reqs, e.scanmisses-b.scanmisses scan_miss, e.modifications-b.modifications mod_reqs, e."COUNT" , e.usage cur_usage, e.fixed fixed from stats$begin_dc b, stats$end_dc e where b.cache#=e.cache# and nvl(b.subordinate#,-1) = nvl(e.subordinate#,-1)

and b.test=counter and e.test=counter;insert into hist$lib select counter, e.namespace, e.gets-b.gets gets,e.gethits-b.gethits gethits,

e.pins-b.pins pins, e.pinhits-b.pinhits pinhits, e.reloads - b.reloads reloads, e.invalidations - b.invalidations invals from stats$begin_lib b, stats$end_lib e where b.namespace = e.namespace and b.test=counter and e.test=counter;

commit;end;/

p_bstat.sql

Rem ********************************************************************Rem Gather start statisticsRem ********************************************************************

insert into hist$dates select stat$interval.nextval, 'Start', to_char(sysdate, 'dd-MON-yy hh24:mi:ss') from dual;

insert into stats$begin_stats select stat$interval.currval, v$sysstat.*from v$sysstat;

insert into stats$begin_dc select stat$interval.currval, v$rowcache.*from v$rowcache;

insert into stats$begin_lib select stat$interval.currval, v$librarycache.*from v$librarycache;

insert into stats$begin_latch select stat$interval.currval, v$latch.*

Page 40: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-40 ORACLE CONFIDENTIAL , Release 7.3

from v$latch;

insert into stats$begin_event select stat$interval.currval, v$system_event.*from v$system_event;

commit;

p_estat.sqlThis script calls the estat procedure and gathers statistis and summary data.

execute estat;

p_query.sql

This script creates a report reflecting the statistics and hit ratios of the most recent run.

spool resultsset echo onset pagesize 60set linesize 80set numwidth 10

spool report.txtRem Select Library cache statistics. The pin hit rate shoule be high.column "Gethit%" format 90.999column "Pinhit%" like gethitratiocolumn reloads format 9,999,990column invals like reloadsselect namespace library, gets, round(decode(gethits,0,1,gethits)/decode(gets,0,1,gets),3) "Gethit%", pins, round(decode(pinhits,0,1,pinhits)/decode(pins,0,1,pins),3) "Pinhit%", reloads, invals from hist$lib where test = (select max(a.test) from hist$lib a);

set numwidth 8;column name format a25;column "Gethit%' format 90.999Rem Select Dictionary Cache (rowcache) StatisticsRem get_miss and scan_miss should be very low compared to the requests.Rem cur_usage is the number of entries in the cache that are being used.select name, get_reqs, get_miss, scan_reqs, scan_miss, mod_reqs, count, cur_usage, round((get_reqs-get_miss)/decode(get_reqs,0,1,get_reqs),3) "Gethit%" from hist$dc where get_reqs != 0 or scan_reqs != 0 or mod_reqs != 0 and test= (select max(test) from hist$lib);

Page 41: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-41

set numwidth 12;column "Statistic" format a45Rem The total is the total value of the statistic between the timeRem bstat was run and the time estat was run.column "Statistic" format a40select n1.name "Statistic", n1.change "Total", decode(trans.change, 0, 0, round(n1.change/trans.change,2)) "Per Txn", decode(logs.change, 0, 0, round(n1.change/logs.change,2)) "Per Logon" from hist$stats n1, hist$stats trans, hist$stats logs where trans.name='user commits' and logs.name in ('cumulative logons', 'logons cumulative') and n1.change != 0 and n1.test=trans.test and trans.test=logs.test and n1.test = (select max(test) from hist$lib) order by n1.name;

set numwidth 10;column "Event Name" format a40column "Avg Time Waited" format 9,990.999Rem System wide wait events.select n1.event "Event Name", n1.event_count "Count", n1.time_waited "Time Waited", (n1.time_waited/n1.event_count) "Avg Time Waited" from hist$event n1 where n1.event_count > 0 and n1.test = (select max(test) from hist$lib) order by n1.time_waited desc;

set numwidth 27Rem Average length of the dirty buffer write queue. If this is larger thanRem the value of the db_block_write_batch init.ora parameter, then considerRem increasing the value of db_block_write_batch and check for disks thatRem are doing many more IOs than other disks.select queue.change/writes.change "Average Write Queue Length" from hist$stats queue, hist$stats writes where queue.name = 'summed dirty queue length' and writes.name = 'write requests' and queue.test=writes.test and queue.test = (select max(test) from hist$lib);

set numwidth 11;column latch_name format a30column hit_ratio format 90.999column "SLEEPS/MISS" like hit_ratioRem Sleeps should be low. The hit_ratio should be high.select name latch_name, gets, misses, round(decode(gets-misses,0,1,gets-misses)/decode(gets,0,1,gets),3) hit_ratio, sleeps, round(sleeps/decode(misses,0,1,misses),3) "SLEEPS/MISS" from hist$latches where gets != 0 and

Page 42: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-42 ORACLE CONFIDENTIAL , Release 7.3

test = (select max(test) from hist$lib) order by name;

set numwidth 12column latch_name format a30column hit_ratio format 90.999Rem Statistics on no_wait gets of latches. A no_wait get does not wait for theRem latch to become free, it immediately times out.select name latch_name, immed_gets nowait_gets, immed_miss nowait_miss, round(decode(immed_gets-immed_miss,0,1,immed_gets-immed_miss)/ decode(immed_gets,0,1,immed_gets), 3) hit_ratio from hist$latches where immed_gets != 0 and test = (select max(test) from hist$lib) order by name;

column Name format a40column Value format a20Rem The non-default init.ora parameters currently in effect:select ksppinm Name, ksppivl Value from x$ksppi where ksppidf = 'FALSE' order by ksppinm;

column name format a30;column value format 9,999,990.999PRset null 0Rem Display key ratios from the generated statistics.select * from stats$ratios;

column type format a10column stats_gather_times format a20Rem The times that bstat and estat were run.select * from stats$dates;

spool off;

comp_ratios.sql

This script generates some key ratios for BSTAT/ESTAT analysis. This script will populate the comp_ratio table.

declarecons_gets number;dblk_gets number;total_gets number;phy_reads number;phy_writes number;lcache number;

Page 43: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-43

rcache number;rdo_sreq number;rdo_retry number;rdo_ent number;rdo_size number;rbs_wait number;bbwaits number;fbwaits number;lch_miss number;lch_imiss number;tfcont_row number;tfby_rid number;tsrow_got number;fbuff_ins number;fbuff_req number;cum_cur number;sort_dsk number;sort_mem number;sort_row number;usr_roll number;usr_com number;rec_calls number;usr_calls number;parse_cnt number;dbwr_cross number;dbfree number;dbmkfree number;dbscan number;dblru number;bg_stats date;en_stats date;sum_req number;wr_req number;stat_time number;counter number;

beginselect max(test) into counter from hist$stats;

begin select change into cons_gets from hist$stats where name = 'consistent gets' and test=counter; exception when no_data_found then cons_gets:=1; end; begin select change into dblk_gets from hist$stats where name = 'db block gets' and test=counter; exception when no_data_found then dblk_gets:=1; end;total_gets:= cons_gets + dblk_gets; begin select change into phy_reads from hist$stats where name = 'physical reads' and test=counter; exception when no_data_found then

Page 44: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-44 ORACLE CONFIDENTIAL , Release 7.3

phy_reads:=1; end; begin select change into phy_writes from hist$stats where name = 'physical writes' and test=counter; exception when no_data_found then

phy_writes:=1; end; begin select change into rdo_sreq from hist$stats where name = 'redo log space requests' and test=counter; exception when no_data_found then

rdo_sreq:=1; end; begin select change into rdo_ent from hist$stats where name = 'redo entries' and test=counter; exception when no_data_found then

rdo_ent:=1; end; begin select change into rdo_retry from hist$stats where name = 'redo buffer allocation retries' and test=counter; exception when no_data_found then rdo_retry:=1; end; begin select change into rdo_size from hist$stats where name = 'redo size' and test=counter; exception when no_data_found then

rdo_size:=1; end; begin select event_count into bbwaits from hist$event where event = 'buffer busy waits' and test=counter; exception when no_data_found then

bbwaits:=1; end; begin select event_count into fbwaits from hist$event where event = 'free buffer waits' and test=counter; exception when no_data_found then

fbwaits:=1; end; begin select change into tfcont_row from hist$stats where name = 'table fetch continued row' and test=counter; exception when no_data_found then

tfcont_row:=1;• end; begin select change into tfby_rid from hist$stats where name = 'table fetch by rowid' and test=counter; exception when no_data_found then

tfby_rid:=1;

Page 45: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-45

end; begin select change into tsrow_got from hist$stats where name = 'table scan rows gotten' and test=counter; exception when no_data_found then

tsrow_got:=1; end; begin select change into fbuff_ins from hist$stats where name = 'free buffer inspected' and test=counter; exception when no_data_found then

fbuff_ins:=1; end; begin select change into fbuff_req from hist$stats where name = 'free buffer requested' and test=counter; exception when no_data_found then

fbuff_req:=1; end; begin select change into cum_cur from hist$stats where name in ('cumulative opened cursors',

'opened cursors cumulative') and test=counter; exception when no_data_found then

cum_cur:=1; end; begin select change into sort_dsk from hist$stats where name = 'sorts (disk)' and test=counter; exception when no_data_found then

sort_dsk:=1; end; begin select change into sort_mem from hist$stats where name = 'sorts (memory)' and test=counter; exception when no_data_found then

sort_mem:=1; end; begin select change into sort_row from hist$stats where name = 'sorts (rows)' and test=counter; exception when no_data_found then

sort_row:=1; end; begin select change into usr_roll from hist$stats where name = 'user rollbacks' and test=counter; exception when no_data_found then

usr_roll:=1; end; begin select change into usr_com from hist$stats where name = 'user commits' and test=counter; exception when no_data_found then

usr_com:=1;

Page 46: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-46 ORACLE CONFIDENTIAL , Release 7.3

end; begin select change into rec_calls from hist$stats where name = 'recursive calls' and test=counter; exception when no_data_found then

rec_calls:=1; end; begin select change into usr_calls from hist$stats where name = 'user calls' and test=counter; exception when no_data_found then

usr_calls:=1; end; begin select change into parse_cnt from hist$stats where name = 'parse count' and test=counter; exception when no_data_found then

parse_cnt:=1; end; begin select (sum(pins) - sum(reloads))/sum(pins) into lcache from hist$lib

where test=counter; exception when no_data_found then

lcache:=1; end; begin select (sum(get_reqs) - sum(get_miss))/sum(get_reqs) into rcache from hist$dc where test=counter; exception when no_data_found then

rcache:=1; end; begin select sum(misses)/sum(gets), sum(immed_miss)/sum(immed_gets)

into lch_miss, lch_imiss from hist$latches where test=counter; exception when no_data_found then

lch_miss:=1;lch_imiss:=1;

end; begin select change into dbwr_cross from hist$stats

where name = 'DBWR cross instance writes' and test=counter; exception when no_data_found then

dbwr_cross:=1; end; begin select change into sum_req from hist$stats

where name = 'summed dirty queue length' and test=counter; exception when no_data_found then

sum_req:=1; end; begin select change into dbfree from hist$stats

where name = 'DBWR free buffers found' and test=counter; exception when no_data_found then

dbfree:=1;

Page 47: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-47

end; begin select change into dbmkfree from hist$stats

where name = 'DBWR make free requests' and test=counter; exception when no_data_found then

dbmkfree:=1; end; begin select change into dbscan from hist$stats

where name = 'DBWR buffers scanned' and test=counter; exception when no_data_found then

dbscan:=1; end; begin select change into dblru from hist$stats

where name = 'DBWR lru scans' and test=counter; exception when no_data_found then

dblru:=1; end; begin select change into wr_req from hist$stats

where name = 'write requests' and test=counter; exception when no_data_found then

wr_req:=1; end; select to_date(stats_gather_times, 'dd-MON-yy hh24:mi:ss') into bg_stats from hist$dates where type='Start' and test=counter; select to_date(stats_gather_times, 'dd-MON-yy hh24:mi:ss') into en_stats from hist$dates where type='End' and test=counter; select 60*24*(en_stats-bg_stats) into stat_time from dual;

-- Compute and insert the ratios into hist$ratios

insert into hist$ratiosselect counter, 'Buffer Cache Hits', (total_gets-phy_reads)/

decode(total_gets, 0, 1, total_gets) ,'(gets - phy_rds)/gets' from dual;

insert into hist$ratiosselect counter,

'Library Cache Pinhits', lcache, '(pins - reloads)/pins'from dual;

insert into hist$ratiosselect counter, 'Row Cache Gets', rcache, '(gets-misses)/gets'from dual;

insert into hist$ratiosselect counter, 'Buffer Busy Waits',

bbwaits/decode(total_gets, 0, 1, total_gets),'buffer waits/logical gets' from dual;

insert into hist$ratiosselect counter,

'Latch Miss', lch_miss ,'latch misses/latch gets' from dual;insert into hist$ratios

select counter, 'Latch NoWait Miss', lch_imiss, 'imm miss/imm gets' from dual;

Page 48: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-48 ORACLE CONFIDENTIAL , Release 7.3

insert into hist$ratiosselect counter,'DBWR Buffers per Scan', dbscan/decode(dblru,0,1,dblru),

'buff scanned/lru scans' from dual;insert into hist$ratios

select counter,'DBWR Reusable Buffers', dbfree/decode(dbmkfree,0,1,dbmkfree),

'free buff found/make free req' from dual;insert into hist$ratios

select counter, 'Free Buffers Inspected',fbuff_ins/decode(fbuff_req,0,1, fbuff_req),'buff inspected/buff req' from dual;

insert into hist$ratiosselect counter,

'Free Buffer Waits', fbwaits/decode(fbuff_req,0,1, fbuff_req),'buff waits/buff req' from dual;

insert into hist$ratiosselect counter,'Dirty Queue Length', sum_req/decode(wr_req,0,1,wr_req),

'sum dirty_q/write req' from dual;insert into hist$ratios

select counter, 'DBWR Ping Traffic',dbwr_cross/decode(phy_writes,0,1, phy_writes),

'cross_inst writes/phy writes' from dual;insert into hist$ratios

select counter, 'Continued Row Access', tfcont_row/decode(tfby_rid+tsrow_got,0,1,tfby_rid+tsrow_got),'chained/(rowid + tscan rows)' from dual;

insert into hist$ratiosselect counter, 'Indexed Row Access', tfby_rid/

decode(tfby_rid+tsrow_got,0,1,tfby_rid+tsrow_got),'rowid/(rowid + tscan rows)' from dual;

insert into hist$ratiosselect counter, 'Sort Overflow', sort_dsk/

decode(sort_dsk + sort_mem,0,1,sort_dsk + sort_mem),'disk/(disk + mem)' from dual;

insert into hist$ratiosselect counter, 'Rows per Sort', sort_row/

decode(sort_dsk + sort_mem,0,1,sort_dsk + sort_mem),'rows/(total sorts)' from dual;

insert into hist$ratiosselect counter,'Cursors Opened per Txn',

cum_cur/decode(usr_com, 0, 1, usr_com),'cursors opened/commits' from dual;

insert into hist$ratiosselect counter,'Recursive/User Calls',

rec_calls/ decode(usr_calls,0,1,usr_calls),'rec calls/user calls' from dual;

insert into hist$ratiosselect counter,'Parses per User Call',

parse_cnt/decode(usr_calls,0,1,usr_calls),'parse count/user calls' from dual;

insert into hist$ratiosselect counter,'Redo Log Space Request', rdo_sreq/decode(rdo_ent,0,1, rdo_ent),

Page 49: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-49

'redo space req/redo entries' from dual;insert into hist$ratios

select counter,'Redo Log Buffer Retry', rdo_retry/decode(rdo_ent,0,1, rdo_ent),

'redo retries/redo entries' from dual;insert into hist$ratios

select counter,'Redo Record Size (avg Bytes)',

rdo_size/decode(rdo_ent,0,1,rdo_ent),'redo size/redo entries' from dual;

insert into hist$ratiosselect counter,'Redo Generation Rate (KB/Min)',

(rdo_size/1024)/decode(stat_time,0,1,stat_time),'redo generated/minute' from dual;

insert into hist$ratiosselect counter,'Transaction Rate (Cmt/Min)',

usr_com/decode(stat_time,0,1,stat_time),'commits/minute' from dual;

commit;end;/

Monitor session or per cursor statistics

This should be ran during and after each test run.

Gather cursor statistics and information:

select sql_text, sharable_mem, persistent_mem, runtime_mem, sorts, version_count,loaded_versions, open_versions, users_opening, executions, users_executing, loads,parse_calls, disk_reads, buffer_gets, row_processed from v$sqlarea whereparsing_schema_id=‘&USERNAME’;

Note: to gather information about a single cursor, replace above where clause with “ sql_text like ‘%cursor text%’ ”.

Gather object dependencies from the object cache.

select s.sql_text, o.owner, o.name, o.namespace, o.sharable_mem, o.loads, locks, pins, keptfrom v$db_object_cache o,v$object_dependency d, v$sql swhere o.owner =d.to_owner and o.name=d.to_name andd.from_address= s.address and d.from_hash= s.hash_value;

Note: to gather information for a single cursor, add this line to the where clause: “and s.sql_text like ‘%cursor text%’ “.

Page 50: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-50 ORACLE CONFIDENTIAL , Release 7.3

INIT.ORA parametersHere is a list of several init.ora parameters that will affect apace allocation and performance of the shared pool. Please referto Oracle 7 Server Reference or Oracle 7 DBA guide for more detailed explanation.

1. closed_cache_open_cursors2. cursor_space_for_time3. open_cursors4. row_cache_cursors5. session_cache_cursors6. sequence_cache_entries7. sequence _cache_hash_buckets8. shared_pool_size9. shared_pool_reserved_size10. _kgl_latch_count11. _kgl_bucket_count

Page 51: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-51

Reserved Shared Pool

RESERVED SPACE FROM THE SHARED POOL

On busy systems, the RDBMS may have difficulty finding a contiguous piece of memory to satisfy a large request formemory. Because the RDBMS will search for and free currently unused memory, the search for this large piece of memorymay disrupt the behavior of the share pool, leading to more fragmentation and poor performance.

RDBMS 7.1.5 allows DBAs to reserve memory within the shared pool to satisfy these large allocations during RDBMSoperations such as PL/SQL compilation and trigger compilation. Smaller objects will not fragment the reserved list, helpingto ensure the reserved list will have large contiguous chunks of memory. Once the memory allocated from the reserved list isfreed, it returns to the reserved list.

The size of the reserved list, as well as the minimum size of the objects that can be allocated from the reserved list arecontrolled via init.ora parameters: shared_pool_reserved_size and shared_pool_reserved_min_alloc.

shared_pool_reserved_sizeThe init.ora parameter shared_pool_reserved_size controls the amount of shared_pool_size reserved for large allocations. Inorder to create a reserved list, shared_pool_reserved_size must be greater than shared_pool_reserved_min_alloc.

units : bytes default: 0 (no reserved list) minimum: > shared_pool_reserved_min_alloc maximum: 1/2 shared_pool_size

shared_pool_reserved_min_allocThe init.ora parameter shared_pool_reserved_min_alloc controls allocation for the reserved memory. Only allocations largerthan shared_pool_reserved_min_alloc are allowed to allocate space from the reserved list if a chunk of memory of sufficientsize is not found on the shared pool's free lists.

units : bytes default: 5000 minimum: 5000 maximum: < shared_pool_reserved_size

The default value for shared_pool_reserved_min_alloc should be adequate for almost all systems.

CONTROLLING SPACE RECLAMATION OF THE SHARED POOLRDBMS 7.1.5 also provides a new procedure, aborted_request_threshold, in package dbms_shared_pool, which allows usersto set the limit on the size of allocations allowed to flush the shared pool if the free lists cannot satisfy the request size.

Before the RDBMS signals the ORA-4031 error, it incrementally flushes unused objects from the shared pool until there issufficient memory to satisfy the allocation request. In most cases, incrementally flushing objects from the shared pool freesenough memory for the allocation to complete succesfully. If the RDBMS signals an ORA-4031 error, it has flushed allobjects currently not in use on the system without finding a large enough piece of contiguous memory.

Page 52: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-52 ORACLE CONFIDENTIAL , Release 7.3

On a busy system, the larger the space allocation, the more likely the RDBMS will signal the ORA-4031 error. Flushing allobjects, however, will impact other users on the system, possibly causing a degradation in performance.

The aborted_request_threshold procedure allows the DBA to localize the impact the ORA-4031 error to the process thatcouldn't allocate memory. The procedure takes a numeric value between 5000 and 2147483647, representing the size, inbytes, of the threshold.

NEW FIXED VIEW V$SHARED_POOL_RESERVEDRDBMS 7.1.5 has a new fixed view to help tune the reserved pool and space within the shared pool. The name of the newfixed view is V$SHARED_POOL_RESERVED and has the following columns:

Name Null? Type------------------------------- -------- --------------FREE_SPACE NUMBERAVG_FREE_SIZE NUMBERFREE_COUNT NUMBERMAX_FREE_SIZE NUMBERUSED_SPACE NUMBERAVG_USED_SIZE NUMBERUSED_COUNT NUMBERMAX_USED_SIZE NUMBERREQUESTS NUMBERREQUEST_MISSES NUMBERLAST_MISS_SIZE NUMBERMAX_MISS_SIZE NUMBERREQUEST_FAILURES NUMBERLAST_FAILURE_SIZE NUMBERABORTED_REQUEST_THRESHOLD NUMBERABORTED_REQUESTS NUMBERLAST_ABORTED_SIZE NUMBER

These columns of V$SHARED_POOL_RESERVED are only valid if the parameter shared_pool_reserved_size is set to avalid value.

FREE_SPACE is the total amount of free space on the reserved list. AVG_FREE_SIZE is the average size of the free memory on the reserved list. FREE_COUNT is the number of free pieces of memory on the reserved list. MAX_FREE_SIZE is the size of the largest free piece of memory on the reserved list. USED_SPACE is the total amount of used memory on the reserved list. AVG_USED_SIZE is the average size of the of the used memory on the reserved list. USED_COUNT is the number of used pieces of memory on the reserved list. MAX_USED_SIZE is the size of the largest used piece of memory on the reserved list. REQUESTS is the number of times that the reserved list was searched for a free piece of memory. REQUEST_MISSES is the number of times the reserved list didn't have a free piece of memory to satisfy the request, andproceeded to start flushing objects from the LRU list. LAST_MISS_SIZE is the request size of the last REQUEST_MISS. MAX_MISS_SIZE is the request size of the largest REQUEST_MISS.

The next set of columns contain values which are valid even if shared_pool_reserved_size is not set.

REQUEST_FAILURES is the number of times that no memory was found to satisfy a request (e.g., number of times ORA-4031 occurred)

Page 53: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-53

LAST_FAILURE_SIZE is the request size of the last failed request (e.g., the request size of last ORA-4031).

ABORTED_REQUEST_THRESHOLD is the minimum size of a request which will signal an ORA-4031 error withoutflushing objects. See the procedure aborted_request_threshold described above.

LAST_ABORTED_SIZE is the last size of the request which returned an ORA-4031 error without flushing objects from theLRU list.

TUNING HINTS BASED ON V$SHARED_POOL_RESERVED

Information in V$SHARED_POOL_RESERVED can help to set values for shared_pool_reserved_size and evenshared_pool_size. This section assumes the DBA has performed all other shared pool tuning on his system.

Initial Value for shared_pool_reserved_sizeThe DBA should make shared_pool_reserved_size 10% of the shared_pool_size. For most systems, this value should besufficient, if the DBA has already spent time tuning the shared pool.

Initial Value for shared_pool_reserved_min_allocIn most cases, the default value (5000 bytes) for this parameter is adequate. If the DBA increases this value, then theRDBMS will allow fewer allocations from the reserved list and will request more memory from the shared pool list.

Tuning shared_pool_reserved_sizeIdeally, shared_pool_reserved_size should be made large enough to satisfy any request scanning for memory on the reservedlist without flushing objects from the shared pool. The amount of operating system memory, however, may constrain thesize of the SGA, and therefore the size of the shared pool such that this is not a feasible goal.

If the DBA has a system with ample free memory to increase his SGA, the goal is to have:

REQUEST_MISS = 0

If the DBA is constrained for OS memory, his goal is:

REQUEST_FAILURES = 0 or not increasing LAST_FAILURE_SIZE > shared_pool_reserved_min_alloc AVG_FREE_SIZE > shared_pool_reserved_min_alloc

If neither of these goals are met, increase shared_pool_reserved_size; the DBA also needs to increase shared_pool_size bythe same amount, since the reserved list is taken from the shared pool.

shared_pool_reserved_size too lowThe reserved pool is too small when:

REQUEST_FAILURES > 0 (and increasing)

and at least one of the following is true:

LAST_FAILURE_SIZE > shared_pool_reserved_min_alloc

Page 54: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-54 ORACLE CONFIDENTIAL , Release 7.3

MAX_FREE_SIZE < shared_pool_reserved_min_alloc FREE_MEMORY < shared_pool_reserved_min_alloc

The DBA has two options, depending on his SGA size constraints:

o Increase shared_pool_reserved_size and shared_pool_size, accordingly o Increase shared_pool_reserved_min_alloc (but may need to increase shared_pool_size)

The first option will increase the amount of memory available on the reserved list without impacting users not allocatingmemory from the reserved list. The second options reduces the number of allocations allowed to use memory from thereserved list; doing so, however, will increase normal shared pool perhaps impacting other users on the system.

shared_pool_reserved_size too highIt is possible that too much memory has been allocated to the reserved list. If:

REQUEST_MISS = 0 or not increasing FREE_MEMORY = > 50% of shared_pool_reserved_size minimum

The DBA has two options:

o Decrease shared_pool_reserved_size o Decrease shared_pool_reserved_min_alloc (if not the default value)

shared_pool_size too smallThe new fixed table can also indicate when shared_pool_size is too small. If:

REQUEST_FAILURES > 0 and increasing LAST_FAILURE_SIZE < shared_pool_reserved_min_alloc

Then the DBA has two options if he has enabled the reserved list:

o Decrease shared_pool_reserved_size o Decrease shared_pool_reserved_min_alloc (if set larger than the default)

Otherwise, the DBA the could:

o Increase shared_pool_size

Procedure free_unused_memory

This text is also in the specification for this procedure in dbmsutil.sql. It is part of package dbms_session.

Procedure free_unused_memory --

Procedure for users to reclaim unused memory after performing operations requiring large amounts of memory (where largeis >100K). Note that this procedure should only be used in cases where memory is at a premium.

Examples operations using lots of memory are:

Page 55: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-55

o large sorts where entire sort_area_size is used and sort_area_size is hundreds of KB o compiling large PL/SQL packages, procedures, or functions o storing hundreds of KB of data within PL/SQL indexed tables

One can monitor user memory by tracking the statistics "session uga memory" and "session pga memory" in thev$sesstat/v$statname fixed views. Monitoring these statistics will also show how much memory this procedure has freed.The behavior of this procedure depends upon the configuration of the server operating on behalf of the client:

o dedicated server - returns unused PGA memory to the OS o MTS server - returns unused session memory to the shared_pool

In order to free memory using this procedure, the memory must not be in use.

Once an operation allocates memory, only the same type of operation can reuse the allocated memory. For example, oncememory is allocated for sort, even if the sort is complete and the memory is no longer in use, only another sort can reuse thesort-allocated memory. For both sort and compilation, after the operation is complete, the memory is no longer in use andthe user can invoke this procedure to free the unused memory.

An indexed table implicitly allocates memory to store values assigned to the indexed table's elements. Thus, the moreelements in an indexed table, the more memory the RDBMS allocates to the indexed table. As long as there are elementswithin the indexed table, the memory associated with an indexed table is in use.

The scope of indexed tables determines how long their memory is in use. Indexed tables declared globally are indexed tablesdeclared in packages or package bodies. They allocate memory from session memory. For an indexed table declaredglobally, the memory will remain in use for the lifetime of a user's login (lifetime of a user's session), and is freed after theuser disconnects from ORACLE.

Indexed tables declared locally are indexed tables declared within functions, procedures, or anonymous blocks. Theseindexed tables allocate memory from PGA memory. For an indexed table declared locally, the memory will remain in usefor as long as the user is still executing the procedure, function, or anonymous block in which the indexed table is declared.After the procedure, function, or anonymous block is finished executing, the memory is then available for other locallydeclared indexed tables to use (i.e., the memory is no longer in use).

Assigning an uninitialized, "empty," indexed table to an existing index table is a method to explicitly re-initialize the indexedtable and the memory associated with the indexed table. After this operation, the memory associated with the indexed tablewill no longer be in use, making it available to be freed by calling this procedure. This method is particularly useful onindexed tables declared globally which can grow during the lifetime of a user's session, as long as the user no longer needsthe contents of the indexed table.

The memory rules associated with an indexed table's scope still apply; this method and this procedure, however, allow usersto intervene and to explictly free the memory associated with an indexed table.

The PL/SQL fragment below illustrates the method and the use of procedure free_unused_user_memory.

create package foobar type number_idx_tbl is table of number indexed by binary_integer; store1_table number_idx_tbl; -- PL/SQL indexed table store2_table number_idx_tbl; -- PL/SQL indexed table store3_table number_idx_tbl; -- PL/SQL indexed table ... end; -- end of foobar declare ... empty_table number_idx_tbl; -- uninitialized ("empty") versionbegin

Page 56: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-56 ORACLE CONFIDENTIAL , Release 7.3

for i in 1..1000000 loop store1_table(i) := i; -- load data end loop; ... store1_table := empty_table; -- "truncate" the indexed table ... - dbms_session.free_unused_user_memory; -- give memory back to system

store1_table(1) := 100; -- index tables still declared; store2_table(2) := 200; -- but truncated. ... end;

Performance Implication:

This routine should be used infrequently and judiciously.

Page 57: Shared Pool Internals

Technical Reports Compendium, Volume I, 1996 Shared Pool Internals

ORACLE CONFIDENTIAL, Release 7.3 4-57

Section Six: Shared Pool Bugs

bug 322904 heavy memory usage may cause severe performance degradation or database hang

introduced in 7.2

On a site with heavy memory usage (things are getting kicked out of the hared pool consistently) the processes requestingmemory can get into a state where they keep interupting each other's searches through the LRU list looking for chunks tofree. This happens because the process currently holding the shared pool latch modifies the list. The culprit of this problemare KGL handles of objects that have dependencies on ther objects protected under different KGL latches. As these types ofhandles build up on the LRU list, the problem progressively gets worse until the system hangs. The system may be freed upevery so often when someone gets a parent latch and frees up some these problem handles. The real fix is going into 7.3.Any backport of this fix to 7.2 (note the problem is introduced in 7.2) should also include the fix to bug #318582.

fixed in 7.3fix checked into 7.3.2 kgl2.c rev. 1.102

bug 318582 Handles and memory (shared pool) can not be freed resulting ora 4031

Introduced in 7.2.2

Problem:Sites may run into this if they are not sharing cursors. Here is an explanation of the problem: The library cache now has twotypes of latches, the parent latch and one or more child latches. When the parent latch is held, all child latches are effectivelyheld. Each library cache object is made up of a KGL handle and number of "heaps", the first being heap 0. Heap 0 is specialbecause it contains control information about the other heaps making up the library cache object. When the heap managerrequests that some space be freed, it asks that the handle, heap 0 , and other heaps be freed individually. Before calling backto the library cache, the heap manager has to grab the appropriate child latch, or in some cases the parent latch,corresponding the memory to be freed. Here is the new behavior in KGL starting in 7.2...

1. When a handle is requested to be freed, it will not be freed if the parent latch is not held and heap 0 still is loaded.2. heap 0 can only be freed if the parent latch is obtained.3. If a child latch is held when the memory request that ultimately causes some memory to be freed is made, theparent latch cannot be obtained.

.In most cases, heap 0 and the handle make up a small percentage of the memory in the library cache. But when cursors arenot shared, as in the testcase, these objects can use up significant amounts of memory. Now here is the situation where theerror can occur. If there are enough handles and heap 0's in memory such that a memory request can not be satisified withoutkicking some these objects out AND the memory request is made with a child latch held, the following things happen.

1. The Heap 0's cannot be freed because the child latch prevents the heap manager from getting the parent latch.2. The handles can't be freed because the heap 0's are still around.3. No memory is freed and the ORa-4031 error occurs..

Heap 0 needs the parent latch because it might have references to other objects in the library cache protected by differentchild latches. However, most objects do not have these references. The fix is to keep track of the objects that have foreignlatch references and only require the parent latch to free heap 0 for those objects.

Fixed in 7.2.3kgl.c rev. 1.180.720.13 kgl2.c rev. 1.75.720.16

Page 58: Shared Pool Internals

Shared Pool Internals Technical Reports Compendium, Volume I, 1995

4-58 ORACLE CONFIDENTIAL , Release 7.3

bug 309484 Library cache hashing algorithm is causing hanging problems.

Problem.Hashing on the first and last 256 bytes improved performance but did not catch all occurences of sql hashing to the samebucket. A new patch which uses the old hashing algorithm has been given to osd-esc. This new hashing function is fillingup several hash links to quickly even though the objects are different. In some cases the sql they are running is hashing tothe same value. This is where the first 64 bytes and last 64 bytes of each statement are identical.

debugging techniques:alter session set events 'immediate trace name library_cache level 2'; will show hundreds of '*' in some buckets. sults insome buckets filling with thousands of statements.

Fix:@ The 7.2.2 fix for this bug is bundled with fixes for 318582 and 322904@ Please refer to 322904 for 7.2.2 tag

bug 257514 triggers referencing rowids may reference wrong rowid if done recursively

Introduced: 7.1

Problem:The bug occurs because the same trigger is being executed at different pga depths. We make the decision not to rebind thepgaoer->riddef in kxtini() when the cursor holding the trigger text has already been parsed once. This is fine if the pgaoerdoes not change. But each level of pga depth has its own pgaoer structure. The problem is that we are not rebinding to theproper memory location on the stack of pgaoer structures. A higher level example is that if a trigger referencing rowid (orsetting it) is fired by directly issuing a DML statement and then is later fired in the same session by the same SQLstatmentment, but recursively, it may see the wrong rowid.

Fix:Regression testing is occurring.Does not reproduce in 7.3

bugs 192829 and 205976 Pinning Procedures and Triggers with dbms_shared_pool procedure

fixed in 7.1.6

enhancement : Lift 64K limit on the size of packages

Fix:From 7.0.15, the compiled code for a package was split into more than one piece, each piece being only about 12K in size.So, the 64K restriction introduced in 7.0.13 was lifted. Large packages (>100K) may still have problems compiling.

REFERENCES and CREDITS:LIBPOOL.TXT WRITTEN BY JUAN LOAIZAKERNEL GENERIC SHARED LIBRARY CACHE MANAGER (KGL) BY JOYO WIJAYACHAPTER 3 OF PL/SQL - BASED LANGUAGE TECHNOLOGIES (INTERNAL DEVT PAPER)INTERNAL NOTES FROM DEVELOPMENTMULTIPLE LATCHES IN KGL BY AMIT JASUJARDBMS KERNEL CODEORACLE PERFORMANCE TUNING GUIDEMAIL NOTES FROM SERVER TECHNOLOGIES