0% found this document useful (0 votes)
4 views26 pages

Application Programming Using Pooling-1

This document outlines methods for pooling and caching database resources to enhance application performance and scalability, particularly in environments with varying user loads. It covers key concepts such as database sessions, connections, and the importance of connection pooling to manage resources efficiently. The paper also discusses various application programming interfaces and advanced topics related to session management and resource allocation.

Uploaded by

kewal
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views26 pages

Application Programming Using Pooling-1

This document outlines methods for pooling and caching database resources to enhance application performance and scalability, particularly in environments with varying user loads. It covers key concepts such as database sessions, connections, and the importance of connection pooling to manage resources efficiently. The paper also discusses various application programming interfaces and advanced topics related to session management and resource allocation.

Uploaded by

kewal
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 26

Application Programming

Using Pooling and Caching

How to use pooling and caching of database


resources to ensure performance and
scalability

August 2022, Version 1.0


Copyright © 2022, Oracle and/or its affiliates
Public

1 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
Purpose Statement
This paper discusses different mechanisms for pooling and caching database resources to ensure applications
can scale from very few to tens or hundreds of thousands of users. These mechanisms are relevant for simple and
advanced application architectures, including deployments with microservices. This paper focuses primarily on
sessions and SQL statements (cursors), discussing application-side and database-side pooling mechanisms.

Disclaimer
This document in any form, software or printed matter, contains proprietary information that is the exclusive
property of Oracle. Your access to and use of this confidential material is subject to the terms and conditions of
your Oracle software license and service agreement, which has been executed and with which you agree to
comply. This document and information contained herein may not be disclosed, copied, reproduced or
distributed to anyone outside Oracle without prior written consent of Oracle. This document is not part of your
license agreement nor can it be incorporated into any contractual agreement with Oracle or its subsidiaries or
affiliates.

This document is for informational purposes only and is intended solely to assist you in planning for the
implementation and upgrade of the product features described. It is not a commitment to deliver any material,
code, or functionality, and should not be relied upon in making purchasing decisions. The development, release,
and timing of any features or functionality described in this document remains at the sole discretion of Oracle.
Due to the nature of the product architecture, it may not be possible to safely include all features described in this
document without risking significant destabilization of the code.

2 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
Table of Contents

Purpose Statement 2
Disclaimer 2
Introduction 5
Background 5
Part One – Overview 6
Definitions of Database Concepts 6
Database Processes and Memory 6
Database Sessions 6
Database Connections 7
Putting Them Together: Session, Process, and Connection 7
Stateless vs Stateful Sessions 8
The User 8
Part Two – Application Programming 9
Traditional, Dedicated Connections 9
Using a Session Pool 10
Log on for Database Work 10
Database Resident Connection Pooling (DRCP) 11
Using Shared Servers 12
Comparison of the Models 13
Sizing the Pool 13
Part Three - Advanced Topics 14
Using the Client-side Session Pool and DRCP Together 14
Proxy Resident Connection Pooling (PRCP) 15
Using the Client-side Session Pool and PRCP Together 16
Comparison of PRCP and Advanced Configurations 16
Sizing the Combined Pools 17
Batch Processing 17
Statement Caching 17
Using Connection Class with DRCP and PRCP 18
Part Four - Application Programming Interfaces (APIs) 19
Oracle Call Interface (OCI) for C 20
Oracle C++ Call Interface (OCCI) 21
Java JDBC 22
Python cx_Oracle 23
Oracle node.db 24
ODP.NET 24
PHP 24
Part Five – Summary 25
Part Six – Additional Reading 25

3 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
4 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
Introduction
Oracle databases are the core of many applications, serving any type of industry, and covering a vast range of
complexities and deployment sizes. These applications can be anything from small autonomous databases to
massive configurations with multiple Exadata servers, deployed on a vast size range of cloud or on-premises
hardware. These applications can support anywhere from a few concurrent users to millions of concurrent users.
Each of these users can execute a large variety of transactions, including making telephone calls, doing online
shopping, or paying for their goods in supermarkets. These systems are commonly known as On Line Transaction
Processing (OLTP), although they often include batch-oriented processing as well.

The database workload varies in several ways: the number of users may change, the types and mix of activities
may change, and the load from each user may change. One important goal of application programming is to keep
the database safe and fully operational at all times, regardless of any variations in workload. Any user performing
an activity means there is a handle linking the user to the database. To let the database concurrently deal with
large numbers of handles, sharing and pooling is required.

This paper discusses methods of sharing and pooling.

Background
A modern website can support tens to hundreds of thousands—if not millions—of users at any one point in time.
There is often a complex stack involved with the user’s browser or device at one end, networks, firewalls, and
application servers in the middle, and a database server with CPU, memory, and disks at the other end. For each
user spending 10 minutes online browsing a website or an hour making a phone call, the database may only
execute 10 SQL statements, each taking an average of 10ms of database time. To quantify this, assume a user is
online for 1000s—just over 15 minutes—and only uses 100ms of database time. If the database server, having
multiple CPUs and a good I/O subsystem, can provide 10s of database time each wall clock second, it can support
all the database work of 100 users (10s/100ms) in one wall clock second. This means the database can support an
average of 100,000 concurrent users. For this to work, it is critical that the various resources required on the
database server, CPU, memory, and I/O, are efficiently shared between these users.

Database applications that resemble OLTP must therefore always include connection pools. The database must be
protected by only allowing a reasonable number of connections, in a broad sense of the term. If CPU is the
primary resource required, the database connection count should be a low, single digit factor, multiplied by the
number of CPU cores available. Connection pooling is necessary so that precious database resources are shared
and multiplexed between users.

At this point, complexity starts—not only because the term connection pool is vague and has many different
meanings, but also because different parts of the stack support sharing or pooling in several ways. Pooling is
available through database-supported mechanisms such as Database Resident Connection Pooling (DRCP) and
Shared Servers, through a Universal Connection Pool (UCP) or a pooled data source in JDBC, or through OCI1
connection pooling. Connection pools may also be stateless, or stateful. At the surface, these methods all appear
to provide a mechanism for the same end goal, but in practice, they all—either purposefully or inadvertently—
hide the details of what is happening.

The term connection does not have a precise meaning and it is often used as a general concept. In this paper, the
term TCP/IP connection will be used to precisely identify a physical connection with two endpoints of a TCP/IP
socket.

1
The acronym OCI refers to Oracle Call Interface.
5 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
Part One – Overview
Definitions of Database Concepts
Let us start with definitions that help explain what happens during pooling. First, we discuss the use of processes
and memory at the database tier. Then, we explain sessions, which are the core of this paper. We then go on to
the application side and see how the application connects to the database.

Database Processes and Memory


The Oracle database server has a multi-process architecture that uses shared memory. Each of the many
processes perform a specific task and are, grossly speaking, either background processes that do work on behalf
of the whole database and all its connected users, or server processes that do work on behalf of a specific
application or user. All these processes have access to a large, shared memory area called the System Global Area
(SGA), which contains the buffer cache, the shared pool, and other memory structures. The memory specific to
the work done on behalf of a specific user, associated with a session, is called the User Global Area (UGA).

When performing database work—that is, when executing the set of SQL statements that collectively implement
the application—a server process is needed. This server process parses SQL statements, associates names in the
SQL statement with database objects like columns and tables, and transmits data and results between the
application and the database. While doing this, the process has access to the SGA, which contains everything that
can be shared between multiple users, and to the UGA, which is specific to the work being done on behalf of a
specific user.

Background processes handle a large and diversified set of tasks. These tasks may include a process writing
modified blocks in the buffer cache to the database files, an overall process monitor keeping an overview of the
database instance, and a process archiving data to allow for recovery in case database files are lost.2

Database Sessions
A database session is required for any database work to take place. Consider a simple SQL statement:

select * from emp

The database session contains information about the username and password.3 Without the username, emp is
meaningless—it could be a schema with a table named emp, it could be another schema with a synonym named
emp pointing to the table in the first schema, or it could be a schema where emp is a view. Without an
authenticated session—a username logged in with a valid password—emp is meaningless. Authentication is an
important attribute of database sessions.

The database session also contains cursors—handles associated with individual SQL statements. Application
programs typically have many cursors in use concurrently, each associated with different SQL statements or
PL/SQL blocks. If the application needs to execute

select * from dept

as well as

select * from emp where deptno=:1

then two cursors must be open. Application logic determines which cursors to execute in which order. For
example, an order entry system may have different cursors for selecting a customer, inserting order lines,
selecting items, or updating inventory. Some of these cursors may be executed repeatedly if the order contains
multiple order lines.

2
Note that in some cases, such as when Oracle runs on a Microsoft Windows Server, database processes are
actually threads of a single process. This is not further discussed in this paper.
3
Oracle also includes proxy authentication, which is outside the scope of this paper.
6 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
A database session also contains state information associated with the session. Information about inserted or
updated rows is kept until the session does a commit. In cases where a customer places multiple orders,
information about the customer may be kept until the session terminates.

A session is the state saved in memory, containing information about authentication, NLS settings, transactions,
cursors, PL/SQL package variable contents, and similar items. Since the state is merely contents of memory, a
session is not necessarily associated with connections or processes. For example, a session created via the
dbms_scheduler mechanism is wholly independent from users, clients, and application servers, and does not
require a database connection.

Database Connections
In most modern implementations, the application code is executed on systems separated from the database by
TCP/IP networks.4 These systems are often called the application tier and the database tier.5 A database
connection is the two endpoints of a TCP/IP socket, created with Oracle Database's TNS listener process. To
create a connection from a machine to the database server over TCP/IP, you must specify the hostname, a
TCP/IP port number, and the service name. In Oracle's Easy Connect syntax, this is //host:port/service.

Putting Them Together: Session, Process, and Connection


A traditional dedicated client/server connection puts all three concepts together: session, process, and TCP/IP
connection. This is illustrated in Image 1, where the application process is represented by the red circle and the
database process by the yellow circle. The TCP/IP connection is the solid black line, and the arrows represent the
endpoints at the application process and database process.

Image 1: Definition of database concepts

Consider the following SQL*Plus example:

sqlplus username/{password}@//host/service

When you execute the code, four things happen:

1. A process starts on the application side, running the SQL*Plus application code. This is represented by
the red circle.
2. Using the TNS listener running on the database server, a TCP/IP connection is established. This is the
solid black line.
3. The TNS listener starts a server process on the database side. This is a foreground process, represented
by the yellow circle. The end points of the TCP/IP connection are the application and the server process.
4. A session authenticated with your username and password is created in the server process. This is
represented by the green rectangle.
Note the vertical red line in Image 1, which shows the separation between the application tier on the left and the
database tier on the right.

You can now execute SQL statements in SQL*Plus, which are executed using cursors in the UGA. The UGA is
allocated in the Program Global Area (PGA)—memory allocated directly by the server process. When you are
done, you exit SQL*Plus and the session, which releases the TCP/IP connection and the processes.

4
The only exception to this physical network connection is when the application code and the database
code execute on the same system and are connected using Inter Process Communication. This
configuration is not relevant to this paper.
5
Further systems or tiers may exist between the application and the user.
7 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
Stateless vs Stateful Sessions
Sessions have a state associated with them. One consequence of this is that two different users cannot use the
same session. Traditional application programming often associated each user with the whole stack: one
connection, one process, and one session per user. As a result, session state could be kept for a long time and—
for the purpose of this paper—a session could be kept open with a state even when the user was not actively
using the database. This means the database is idle, with no processing happening, waiting for the user to do
something.

The paradigm has changed in modern application programming. The application program either has interaction
with the user, including waiting, or it performs database work, such as executing SQL statements or transactions.
In the periods between doing database work, when the application has interaction with the user, no state is kept in
the database. This means if the user is not actively using the database, they do not have a session open, and there
is no state kept in the database memory. For this reason, this type of application model is often called stateless.
Stateless functionality is when the application actively wraps database calls by acquiring a session from a pool and
returning it to the pool as soon as the database calls are complete. In this paper, this is referred to as a session
pool.6

The benefit of using stateless application programming is clear: sessions in the database are only present or
active when really needed, and as soon as a user completes work, the session is returned to the pool.
Subsequently, the resources held by that session are available to another user. The upper size of the pool can be
limited so that when all sessions in the pool are active, the workload on the database is within the database’s safe
operating limits. When the limit is exhausted, users are put in a queue, waiting for a session to be returned to the
pool by another user.

Why not just allow more sessions? When average users are only active in the database for very brief periods, what
could happen? The problem is the risk of overloading the database, which can cause complete system failure.
Almost everyone has experienced a system being unavailable. In most cases, this is caused by overload: far too
many sessions simultaneously attempting to execute database work, making the system come to an almost
complete halt. During this halt, many database administrators will realize they are unable to do even a simple
logon to their database using SQL*Plus.

The User
The term user is mentioned frequently, and it is important to understand that the user can be more than actual
people. While a user may be a customer at a web shop or a person making a phone call, a user can also be
anything that can initiate an application request, including a physical device like an ATM or a boarding-card
reader at an airport gate. A user’s requests are unpredictable in several ways: how much time will be spent
outside the database? When does the next request arrive? What is the complexity of each request? What can be
predicted, with some certainty, is the average number of requests per time period, along with the distribution of
different types of requests.

6
Note that in literature, documentation, blog posts, etc., this type of application programming is often
referred to as a “stateless connection pool”.
8 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
Part Two – Application Programming
Let us look at these concepts from the practical perspective of the application programmer.
Traditional, Dedicated Connections
A traditional (legacy) programming model is similar to the following:

Sample code 1

database_logon();
loop ...
user_interface();
sql1;
user_interface();
sql2;
commit;
end loop;
database_logoff();

This type of code might execute on a PC, or in a terminal session. The code is executed individually and separately
by each user. While most of the time is spent waiting for the user in user_interface(), the application is often
stateful throughout the whole period, from database logon until logoff. This is represented visually in Image 2:

Image 2: Several traditional applications

The red circles represent the application process of each user, the yellow circles the database process, and the
green rectangles the database session. The arrows between the application process and the database process
represent the TCP/IP connection between them. From a programming perspective, this is very simple, and
typically done using single-threaded programming. This model has a high risk of overloading the database if
many users are active at the same, or almost the same, time.

9 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
Using a Session Pool
Modern application programming uses a very different paradigm that includes a session pool, which looks similar
to the following:

Sample code 2

handle=identify();
loop ...
user_interface();
user_interface();
get_session(handle);
sql1;
sql2;
commit;
release_session(handle);
end loop;

There are several important differences from the traditional programming style. When a modern application
starts—typically when the user logs on to the system—there is often no actual logon to the database. Instead, the
user’s permissions are verified so the subsequent database work can be executed. This is managed by a handle.
When all user interface is complete—typically with the user clicking on “Submit” or similar—a database session is
acquired from the pool via the handle. As soon as database calls are complete, the session is returned to the pool.
There is no session state kept after returning the session.

One popular application programming interface that allows this is Java's Universal Connection Pool (UCP). This is
a multi-threaded interface where each Java process has a number of worker threads running code, and other
threads, maintained by UCP, implementing a pool of sessions. This behaviour is illustrated in Image 3:

Image 3: Client-side session pool

The application side is now multi-threaded. In addition to the worker threads (red), there are certain threads (grey)
that make up the session pool, which consists of TCP/IP connections to the database, each with a server process
and a session. There is now a funnel that allows a high number of application worker threads to share a pool with
a smaller number of database connections, processes, and sessions. This pool has a huge advantage compared to
each client having a dedicated TCP/IP connection: the size of the pool can be configured so that the risk of
overloading the database is reduced, or even completely mitigated. If there are suddenly a high number of worker
threads that need to do database work, they need to queue to get an available session. This queueing does mean
longer execution time seen by the user, but it also helps protect the database from overloading.

Log on for Database Work


The use of a session pool has the benefit of not having a potentially high number of idle processes and sessions
in the database with a high risk of overloading. However, this method requires multi-threaded programming to

10 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
allow for a high number of worker threads sharing a small number of database sessions. If the application code
has a clear separation between the user interface and database work, you can achieve a similar effect by simply
performing a log on to the database whenever database work must be done. This does not require multi-threaded
programming, and means programming something like the following:

Sample code 3

loop ...
user_interface();
user_interface();
database_logon();
sql1;
sql2;
commit;
database_logoff();
end loop;

In principle, this achieves the goal of not having idle processes in the database, but it comes with a very high cost:
performing the database log on. A database log on is expensive: it must establish a TCP/IP connection using the
TNS listener, create an Operating System process, initialize the database environment, verify the username and
password, etc. A log on can easily cost ten or even a hundred times more database time than executing a few SQL
statements. If the SQL that will be executed is simple, the cost of a database logon is prohibitively high.

Batch processing, when many long-running SQL statements are executed, means the cost of log on is minor
compared to that of doing actual database work. One common example of this is extract/transform/load jobs
that are long and database-intensive. This is discussed in Batch Processing, under Part Three - Advanced Topics.

Database Resident Connection Pooling (DRCP)


To circumvent the overhead of database log on while still allowing single-threaded applications to benefit from
session pooling, Oracle provides a mechanism to locate the pool on the database server: database resident
connection pooling, or DRCP. This is similar to using the client-side session pool, as it allows a large number of
worker processes to share a smaller number of database sessions. This is demonstrated in Image 4—note that
only one application process currently has a session:

Image 4: Session pooling using DRCP

The application-side pool of database sessions is replaced by a similar pool in the database server. A broker
process accepts incoming requests for a database session and hands out an available session from its pool. If no
sessions are available, the application waits in the queue unless a new server can be started. When the
application-side process completes its database work, it returns the session to the broker.

In practical terms, DRCP allows a programmer using a single-threaded application that wraps database activity
with an expensive log on and log off to replace those calls with much faster calls that get a session from the
11 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
database-side pool. The use of the handle is similar to the use of application-side pools by multi-threaded
applications, even though the handle is associated with the database-side pool.

As with client-side session pools, the application using DRCP must separate user interface from database work as
shown in Sample Code 2. If you attempt to use DRCP for an application that waits for the user or for a new
application request to arrive while it has a session—that is, between get_session() and
release_session()—you will not achieve any pooling benefits with DRCP. Further, DRCP will disconnect
sessions that are inactive for some time; the time is configured with the max_think_time parameter.

In many cases, it can be beneficial to combine DRCP with client-side session pools, such as UCP. This is discussed
in Using the Client-side Session Pool and DRCP Together in Part Three - Advanced Topics.

Using Shared Servers


Oracle provides another mechanism called Shared Servers to reduce the risk of overloading by having fewer
processes in the database server. Although shared servers appear similar to DRCP, they have different use cases
and benefits. With shared servers, each user has a session in the database—with all the consequences of having a
session. The session state can be kept for a long time while the application is dealing with the user interface, but
the server processes are put into a pool, and therefore shared. This model is shown in Image 5:

Image 5: Shared server

Compared to the traditional model, each individual client process (red) still has a separate database session
(green), but the connection between them is different. There is no longer one TCP/IP connection to a dedicated
database process for each client process—instead, a smaller number of server processes are shared, and the
TCP/IP connection endpoint is a dispatcher process. When a client process, like process 5 in Image 5, is not doing
any database work, there is no activity on its TCP/IP connection. As soon as the client process begins executing
database work, like fetching from a cursor or committing a transaction, the database work is routed from the
dispatcher to one of the available server processes. That process then attaches to the memory structures that
contain the complete session state (the UGA), performs the actual database work, and routes the result back to
the dispatcher. This process is shown in Image 5 by the black arrow from the client to the database state of that
client. The association between the server process and the session memory is then dropped, and the dispatcher
sends the result back to the client side via the TCP/IP connection.

If, at any point in time, client applications attempt to do more database work than there are shared server
processes, the dispatcher places those applications into a queue.

This shared server approach may seem superior to everything described so far: it allows single-threaded
programming, can keep session state for a long time, and reduces the risk of overloading by limiting the number
of server processes. However, there is impact to cost, configuration complexity, and features. For each single
execution of database work—each roundtrip of TCP/IP between the client and the server—there is an extra

12 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
process switch involved, and the total path length is longer. Another extra cost is that for each roundtrip, the
memory of the UGA must be mapped to the actual process. The configuration complexity is that the UGA can no
longer be part of each processes’ memory (PGA). As the actual work done by a session is dealt with by a random
process, the UGA must be available to all processes and therefore is allocated in the SGA, which requires more
complex database administration. Finally, some features, like Exadata smart scan, are not available when using
shared server.

As a result, applications should never be designed to work with shared server. Shared server should only be
considered for existing applications that cannot be modified to have clear separation between user interface and
database work to fit the session pooling model.

Comparison of the Models


We can now compare the different models with respect to application style, programming model, benefits, and
drawbacks.

Table 1: Comparison of application models

Dedicated connection Client-side session DRCP Shared server


pool

Application Any application, including Requires separation of user interface Any


style the traditional model, with from database work, with explicit calls
session state kept for a to get and release sessions; session
long time state (with few exceptions) cannot be
kept after releasing a session.

Programming Any Requires multi- Any Any


model threaded
programming
Benefits Supports traditional Database resources only held while Supports traditional
applications actually in use applications

Drawbacks Database resource held Requires multi- Database Database resources


when not used; high risk threaded resources spent spent pooling;
of database contention programming pooling process switch for
each roundtrip;
complex database
configuration;
several database
features unavailable
Design Useful for batch Preferred design Can be used for Should only be used
considerations operations performing for all OLTP-style OLTP-style for existing
many and/or heavy applications applications if applications that
database calls between multi-threaded cannot use any
log on and log off programming is other model
not an option

Sizing the Pool


What is the proper size of a session pool? Should the pool size be fixed, or variable? One argument is that the pool
should always have room so that it can deal with any increase in load. However, doing so defeats the purpose of
having a pool in the first place, which is to protect the database from overloading. Overloading the database can
happen if otherwise idle sessions start doing database work, or if there is an attempt at starting new database
sessions. If the latter happens rapidly, the result is a connection storm, which can have dramatic consequences
and make the database inaccessible for a long period of time.

In order to keep a database handling an OLTP workload within safe margins, the single most important figure is
the database server CPU utilization. Due to the random nature of OLTP workloads, a typical upper limit for CPU

13 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
utilization is in the order of 60%-65%.7 It is unsafe to operate a database higher than this, and a database
supporting OLTP cannot operate at or close to 100% CPU. To put this in terms of session pool sizing, the largest
number of sessions should be the number of active sessions that bring the database CPU utilization to the safe
upper limit. If the workload increases, the database cannot handle more sessions, which means the user must wait
for a session to become idle. Contrary to common belief, it should never be the goal that sessions are always idle
and available.

In the real world, workload changes for many reasons: it can vary during the day, from one day to another, or
during different periods. Additionally, systems such as application servers may get started and stopped. Ideally,
the database should be shielded from all types of variation, which would be the case if the number of sessions in
the database is never higher than the safe operating limit. Workload variations can then be absorbed without
putting the database at risk. When the workload is low, a get_session will always be honored; when the workload
is at its limit, a get_session will always queue.

Most pooling technologies have several parameters to control the size of the pool, including minimum and
maximum pool sizes, so the pool can grow on demand. Other parameters may control when the pool shrinks, or
the limit for the number of times a session can be released back to the pool before it is disconnected from the
database.

The recommended practice for a single pool with a fixed size that matches the database’s safe upper limit is, in
most cases, not achievable. There will be variations in workload for many different reasons, and completely
avoiding database log on and log off is not possible. Therefore, the ultimate goal for the database administrator is
to reduce the amount of database log on and log off as much as possible.

Part Three - Advanced Topics


Using the Client-side Session Pool and DRCP Together
The most important effect of an application programming style with separation between the user interface and
database is that many users can share a smaller number of database sessions. One way to visualize this is a
funnel. We can therefore define a funnel factor as the ratio between the user count and the session/process count
in the database. There is a practical limit to how large the funnel factor can be. In a modern application
programming case with multi-threaded applications, each application process needs a minimum number of
sessions in its pool. If the number of application processes grows to tens of thousands or more, that minimum
number of sessions can be so high that it risks overloading the database. Even properly designed multi-threaded
applications may require extra measures to protect the database.

An efficient way to do this is to use client-side pooling in combination with DRCP, which gives two funnels as
shown in Image 6:

Image 6: Combining client-side pool with DRCP

7
In some cases, this limit may be even lower.
14 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
The application code is identical to the previously shown multi-threaded code except that the client-side session
pool (such as UCP in Java) connects to the database using DRCP. When a worker thread executes the call to
acquire a session, two things happen:

1. An available session in the process’ own pool is used.


2. That session is, via the DRCP broker, associated with an actual session in the database.
Both steps have a queue, and therefore a potential wait, until a session is started or available. However, once the
session is available to the worker thread, there is no extra overhead. The two queues imply the funnel factor can
be much higher, as the total funnel factor is the product of the funnel factors in the client and in DRCP.

As with cases where either the client-side pool or the single-threaded application uses DRCP, the worker must
release the session as soon as the database work is complete. The session state cannot be kept after release.

Proxy Resident Connection Pooling (PRCP)


Oracle has another technology called Proxy Resident Connection Pool (PRCP) where the pool resides in a proxy
server rather than on the database server. One of the benefits of PRCP is that the resources needed by the pool
itself are separated from the database server, which saves precious database server resources for actual database
work. From the application side, for all practical purposes, PRCP is identical to DRCP. PRCP can be deployed
without any application changes outside of connecting to the server running PRCP rather than the database
server. PRCP is part of Oracle Connection Manager (CMAN), which is installed with a full Oracle Client installation.
Image 7 shows PRCP. In comparison to Image 4, the pooling happens outside the database server:

Image 7: Overview of PRCP

With PRCP, the broker used in DRCP is replaced by multiple threads in multiple processes of the connection
manager. On the outgoing side, threads in the connection manager hold database sessions via TCP/IP
connections to the database. As with DRCP, the clients can be single-threaded. When they acquire a session, they
are assigned one from the pool available inside PRCP. While this saves database resources, as the database no
longer does the pooling, there is an additional network hop between the application and the database.

As before, the client application must separate the user interface and the database work, and it must explicitly
acquire and release database sessions as needed.

15 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
Using the Client-side Session Pool and PRCP Together
Just as a multi-threaded client can have its own pool connected to DRCP, a multi-threaded client can connect its
pool to PRCP. This results in two places where the workers may queue to get a session, and therefore two funnels.
This is shown in Image 8:

Image 8: Using client-side session pool and PRCP together

Note that both images of PRCP show the dedicated mode of operations for PRCP, where each incoming
connection is handled by a dedicated thread. PRCP can also be operated in shared mode, where incoming
connections share a smaller number of threads for incoming traffic. This allows a funnel (and therefore, a queue)
on both the incoming and the outgoing side of PRCP and is not discussed further here.

Comparison of PRCP and Advanced Configurations


We can now supplement the previous comparison chart with the combination of pools and PRCP:

Table 2: Comparison of PRCP and advanced configurations

PRCP Client Pool and DRCP Client Pool and PRCP

Application style Requires application code with explicit session get/release

Programming model Any Requires multi-threaded programming

Benefits Pooling done outside Allows multiple Allows multiple


database applications using session applications using
pools to share a lower session pools to share
number of database a lower number of
sessions database sessions,
with pooling done
outside the database.
Drawbacks Extra network hop Requires multi-threaded Requires multi-
programming; database threading client; extra
resources spent pooling network hop

Deployement Alternative to DRCP for The combination of an application-side session


considerations single-threaded pool and DRCP or PRCP is particularly useful with
applications. microservices or similar configurations with high
number of application servers

16 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
Sizing the Combined Pools
Sizing an individual pool in the application server is complex. When many application servers or microservices,
each with their own pool, are combined with the pools from DRCP or PRCP, the extra pool adds to complexity of
pool sizing.

The goal of protecting the database from overloading is the same in DRCP and PRCP. This can be achieved by
sizing the pool closest to the database so that the database is operating at its safe operating limit when that pool
has reached its maximum and all entries are busy. For DRCP, this constraint puts an upper limit on its size. For
PRCP, the situation is more complex. PRCP consists of a variable number of gateway processes, each with a pool
that has a minimum and maximum size. As with sizing of single pools, there is a tradeoff: you can fix the count of
gateway processes and fix the size of the pool, creating a fixed total pool size, and therefore a fixed number of
database sessions. However, this is inflexible, and may not be useful in real-world production cases.

Further details of combined pool sizing are outside the scope of this paper.

Batch Processing
Batch processing is often characterized as different from OLTP. Rather than having the application alternate
between user interface and database processing, batch processing maintains a queue of only database work for
execution. The queue can be long and may include priorities for different types of workload, but there is a specific
and limited number of processes that perform the actual workload. That number of processes is often set to
ensure the load on the database is controlled.

A major difference between batch processing and OLTP is that a single item (request) in the batch queue typically
requires much more database work than a single OLTP request. This implies the overhead of doing an actual
database log on and log off for each request is small in comparison to the request itself, and there is no need to
use a session pool.

Statement Caching
In a database session, SQL statements are executed in the context of a session by using a cursor—a handle
between a specific session and data stored in memory, and associated with that particular SQL statement. For the
topics discussed here, a cursor contains two primary parts: one part that can be shared between all sessions using
the same cursor, and a second part that has all data relevant for a specific execution of the statement.

The first part contains the actual SQL statement text, the parsed representation of it, and information about the
objects it is processing, all stored in the shared pool in the SGA.

Consider a cursor associated with the following SQL statement:


select e.ename, d.dname, e.sal, e.comm from
emp e join dept d
on e.deptno = d.deptno
where e.sal > :1

The first, shared part of the cursor contains information about the tables emp and dept, instructions for
performing the join, the fact one placeholder (:1) exists, and similar information.

The second part of the cursor includes different values for the placeholder :1, different fetched rows, and other
similar information, specific to each session. This is stored in the session UGA.

When a query like this is executed, three things happen:

1. The SQL text is sent to the database, which parses the cursor into an internal parse tree and associates
database objects, such as tables and indexes, with names in the SQL text.
2. The session specific value for the placeholder :1 is sent to the database
3. The rows returned are fetched and sent to the application.
The database can deal with the first of these steps in two ways. If the SQL statement does not already exist in the
shared pool, the database parses the statement, identifies the objects, and verifies that the user has appropriate

17 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
access. If the SQL statement already exists in the shared pool, only the last part—verifying the user has access—is
needed. The former is called a hard parse, the latter a soft parse.8

The hard parse can require many database resources, while the soft parse typically requires only a few resources.
In OLTP applications, the same SQL statement is likely to be repeated frequently from various parts of the
application. As no actual data processing take place during the parse, the application should avoid this if possible.
Only steps 2 and 3 should be done repeatedly, as these are the steps that do real processing of data.

To reach this goal, the application programmer must ensure frequently executed SQL is parsed as rarely as
possible, which requires holding onto session state (the parsed cursor) for as long as possible. Consider the
previously mentioned application coding model:
loop ...
user_interface();
user_interface();
get_session(handle);
sql1;
sql2;
commit;
release_session(handle);
end loop;

There are two goals that cannot be met: state must be kept to avoid parsing the SQL statements, but state cannot
be kept after releasing the session. However, these two contradictory goals can be met as the application
programming interface itself can keep a cache of open cursors. All application programming interfaces (APIs)
that include session pooling also include a cursor cache. To correctly use the cursor cache, the application
programmer must identify the SQL statements as one of these two categories:

1. The SQL statement is likely to be executed again


2. The SQL statement is likely only executed once
In the former case, the API can cache the SQL statement; in the latter case, it will not. In database terms, caching
the SQL statement means the cursor is kept open and parsed in the database, ready to be executed. If the
application programmer is unable to categorize the SQL, it is recommended to always use the first category,
implying the cache will be controlled by the cursor cache of the API.

The goal of the API’s cursor or statement cache is to reduce parsing, so how large should the cache be? The
answer is “large enough to contain all frequently executed SQL statements”. However, it is difficult to calculate or
predict what this size might be. If set too low, parsing has a high and visible impact on database scalability. If set
too high, there is a risk of keeping cursors open that do not need to be kept open, wasting memory.

Different APIs have different ways to set the size of the cursor cache. Ideally, the size should be an application-
side parameter that can be adjusted based on use of the application. The actual amount of parsing can be found
in Application Workload Repository (AWR) reports that include counts of parse and execute for each statement, as
well as the amount of CPU being used for parsing. It is outside the scope of this paper to give precise guidance on
this, but if the most frequently executed statements have high parse counts or if high CPU time is used for
parsing compared to execution, you should investigate the cursor cache sizes to see if they need to be increased.

Using Connection Class with DRCP and PRCP


DRCP and PRCP pools are shared by many different applications and users, and the connection class is used to
divide the total pool. To allow sharing among similar or identical applications, such as microservices, they need to
explicitly set the same connection class.

8
This is a simplified explanation of how cursors are processed by the database.
18 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
Part Four - Application Programming Interfaces (APIs)
The following tables list ways the concepts discussed in this paper can be implemented using various Oracle
Application Programming Interfaces (APIs). Note that information here is limited, focused on the most important
elements, and the APIs have many additional features not discussed here. You should always consult relevant
documentation for a complete feature list.

For each API, the table describes how to:

• do the initial setup that creates the pool, potentially using DRCP or PRCP via handle=identify()
pseudocode
• set the size of the statement (cursor) cache
• get a session from the pool via get_session(handle) pseudocode
• release the session back to the pool via release_session(handle) pseudocode
• Identify a SQL statement as frequently executed, causing the API to cache it
• Identify a SQL statement as rarely executed, causing the API to not cache it
• terminate the pool
For the initial setup, you provide a connection string that points to an entry in the tnsnames.ora file or use URL-
style syntax. If the entry in tnsnames.ora does not include (server=pooled) or the URL-style connect string
does not have :pooled, the result will be dedicated9 connections to the database without DRCP/PRCP. If you have
configured DRCP or PRCP and want your connection to use it, the entry in tnsnames.ora should include
(server=pooled) or the URL-style connect string should have :pooled.

Note that single-threaded applications can only achieve pooling when using DRCP or PRCP.

Each of the following API descriptions include documentation links.

9
If the database is configured with shared server, shared server will be the default. To make sure dedicated
connections are used, use (server=dedicated) in the tnsnames.ora entry or :dedicated in the URL style
syntax.
19 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
Oracle Call Interface (OCI) for C
Table 3: Oracle Call Interface (OCI) for C

Operation OCI Calls Needed

Initial setup Call OCISessionPoolCreate with sessMin, sessMax, sessIncr set


appropriately and save pstring/pslen returned.
In single-threaded applications using DRCP or PRCP for pooling, set sessMin to
0 or 1 and sessMax to 1. Use a connect string pointing to a pooled server.
In multi-threaded applications doing pooling in the application and using DRCP
or PRCP, use a connect string pointing to a pooled server.
Statement cache Set OCI_ATTR_SPOOL_STMTCACHESIZE to appropriate value.

Get session from pool If using DRCP or PRCP, set OCI_ATTR_CONNECTION_CLASS in OCIAuthInfo.
Call OCISessionGet using pstring/pslen returned from
OCISessionPoolCreate.

Release session Call OCISessionRelease.

Mark SQL for caching Use OCIStmtPrepare2 to prepare the SQL statement and OCIStmtRelease with
OCI_DEFAULT to release it.

Mark SQL to not be Use OCIStmtPrepare2 to prepare the SQL statement and OCIStmtRelease with
cached OCI_STRLS_CACHE_DELETE to release it without caching.

Termination Call OCISessionPoolDestroy.

Documentation https://docs.oracle.com/en/database/oracle/oracle-
database/21/lnoci/session-and-connection-pooling.html#GUID-F9662FFB-
EAEF-495C-96FC-49C6D1D9625C

20 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
Oracle C++ Call Interface (OCCI)
Table 4: Oracle C++ Call Interface (OCCI)

Operation OCCI methods to be invoked

Initial setup Invoke Environment::createStatelessConnectionPool with minConn,


maxConn, incrConn set appropriately.
In a single-threaded application using DRCP or PRCP for pooling, set minConn
to 0 or 1 and maxConn to 1. Use a connect string pointing to a pooled server.
In multi-threaded applications doing pooling in the application and using
DRCP or PRCP, use a connect string pointing to a pooled server.
Statement cache Set using StatelessConnectionPool::setStmtCacheSize.

Get session from pool Invoke StatelessConnectionPool::getConnection.


If using DRCP or PRCP, provide connectionClass to the getConnection
method.

Mark SQL for caching Done by default when the Connection::terminateStatement() method is
invoked.

Mark SQL to not be Explicitly turn off caching by invoking Statement::disableCaching() on the
cached statement object before invoking the Connection::terminateStatement()
method.

Release session Invoke StatelessConnectionPool::releaseConnection.

Termination Invoke Environment::termimnateStatelessConnectionPool.

Documentation https://docs.oracle.com/en/database/oracle/oracle-
database/21/lncpp/accessing-oracle-database-using-cplusplus.html#GUID-
3F1B3810-8FE3-46EB-92D0-49C077B92261

21 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
Java JDBC
For applications written in Java using JDCB, session pooling is provided via a Universal Connection Pool (UCP)
that contains a pooled data source.

Table 5: Java JDBC

Operation UCP methods to invoke

Initial setup Initialize the pooled data sources using


PoolDataSourceFactory.getPoolDataSource(); set the size appropriately by
invoking, then use setMinPoolSize, setMaxPoolSize methods.
In multi-threaded applications doing pooling in the application and using DRCP
or PRCP, use a connect string pointing to a pooled server.
In single-threaded applications using DRCP or PRCP for pooling, use
setMinPoolSize with a value of 0 or 1 and setMaxPoolSize with a value of 1.
Use a connect string pointing to a pooled server.

Statement cache Enable implicit statement caching by invoking


setImplicitCachingEnabled(true) on the OracleDataSource and set the size
by invoking setStatementCacheSize on the connection.

Get session from pool If using DRCP or PRCP, set the connection class using the
oracle.jdbc.DRCPConnectionClass property.
Invoke the getConnection() method of the pooled data source, which returns a
connection in terms of UCP.

Release session Use the close() method of the connection

Mark SQL for caching Statements are implicitly cached when declared using PreparedStatement.

Mark SQL to not be Explicitly invoke setDisableStmtCaching(true) of your PreparedStatement.


cached

Termination Done implicitly in the destructor of the pooled data source.

Documentation https://docs.oracle.com/en/database/oracle/oracle-
database/21/jjucp/intro.html

22 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
Python cx_Oracle
The cx_Oracle.session_pool object is used.

Table 6: Python cx_Oracle

Operation Methods to be invoked

Initial setup Use cx_Oracle.SessionPool, which returns a session pool object; specify pool min
and max sizes.
In multi-threaded applications doing pooling in the application and using DRCP or
PRCP, use a connect string pointing to a pooled server.
In single-threaded applications using DRCP or PRCP for pooling, specify a pool min size
of 0 or 1 and pool max size of 1, and use a connect string pointing to a pooled server.

Statement Set the stmtcachesize attribute of the session pool object


cache

Get session Use the acquire() method of the session pool object.
from pool If using DRCP or PRCP, call the acquire() method with cclass as a text string and
with purity=cx_Oracle.ATTR_PURITY_SELF.

Release session Use the release() method of the session pool object.

SQL caching This is always enabled.

Termination Use the close() method of the session pool object with force=True.

Documentation https://cx-
oracle.readthedocs.io/en/latest/user_guide/connection_handling.html#connection-
pooling

23 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
Oracle node.db
Table 7: Oracle node.db

Operation Methods to be invoked

Initial setup Use the createPool method of the oracledb class and provide values
for poolMin, poolMax, poolIncrement and stmtCacheSize. If using
DRCP or PRCP, the connection class is set as the connectionClass
attribute of the oracledb class.

Statement cache Provided as argument to the createPool method.

Get session from pool Done using the getConnection() method of the oracledb class.

Release session Call the close() method of the connection class.

Mark SQL for caching This is done by default with a statement cache of 30.

Mark SQL to not be cached When executing the SQL, the cache can be excluding using the
execution time flag:
{ keepInStmtCache: false }.
Termination Implicitly done via destructors.

Documentation https://oracle.github.io/node-oracledb/doc/api.html#connpooling

ODP.NET
ODP.NET does not explicitly support session pooling. However, you can use DRCP (or PRCP) with ODP.NET. See
https://docs.oracle.com/en/database/oracle/oracle-database/21/odpnt/featConnecting.html#GUID-757A465B-
4025-4550-8F13-EA92FE0C1B5A for details.

PHP
PHP does not directly expose session pooling and the recommended persistent connections keep the database
connection and session open for the entire execution time of the process. You can use DRCP (or PRCP) as
documented at https://www.php.net/manual/en/oci8.connection.php with the connection class set as
documented at https://www.php.net/manual/en/oci8.configuration.php.

24 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
Part Five – Summary
The Oracle database is designed to support a large and diverse variation of applications, transaction volumes, and
sizes. As the database is a central part of all systems, shielding it from the effects of predicted or unpredicted
variations should be high priority for any deployment. The complete Oracle software stack is developed to
support this shielding. The many diverse APIs available also support a design model that allows the software
developer to produce applications that very effectively can shield and protect the database.

This technical brief gives an overview of application design with particular focus on methods for pooling and
sharing of database resources. It also provides a list of actual procedures or methods for a large number of
popular programming environments including C, Java, Python, and many more.

Part Six – Additional Reading


In addition to the documentation references for each API above, the following documents are relevant.

Table 8: Additional reading

Topic Reference URL

Oracle Database https://docs.oracle.com/en/database/oracle/oracle-


Architecture database/21/cncpt/introduction-to-oracle-database.html

DRCP https://docs.oracle.com/en/database/oracle/oracle-
database/21/jjdbc/database-resident-connection-pooling.html

PRCP https://docs.oracle.com/en/database/oracle/oracle-
database/21/netag/configuring-oracle-connection-manager.html (sections 10.2.4
and 10.5)
https://www.oracle.com/a/tech/docs/cman-tdm-oracle-db-connection-proxy-
for-scalable-apps.pdf

General Michael Hallas, Oracle Real World Performance Team, Understanding the Impact
information about of Cloud Networking on Your Database Applications (nocoug.org), NoCOUG
session pooling Virtual Conference 2020

25 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public
August 2022
Author: Bjørn Kisbye Engsig
Contributing Authors: Christopher Jones

Connect with us

Call +1.800.ORACLE1 or visit oracle.com. Outside North America, find your local office at: oracle.com/contact.

blogs.oracle.com facebook.com/oracle twitter.com/oracle

Copyright © 2020, Oracle and/or its affiliates. All rights reserved. This document is Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be
provided for information purposes only, and the contents hereof are subject to change trademarks of their respective owners.
without notice. This document is not warranted to be error-free, nor subject to any
Intel and Intel Xeon are trademarks or registered trademarks of Intel Corporation. All SPARC
other warranties or conditions, whether expressed orally or implied in law, including
trademarks are used under license and are trademarks or registered trademarks of SPARC
implied warranties and conditions of merchantability or fitness for a particular
International, Inc. AMD, Opteron, the AMD logo, and the AMD Opteron logo are trademarks or
purpose. We specifically disclaim any liability with respect to this document, and no
registered trademarks of Advanced Micro Devices. UNIX is a registered trademark of The Open
contractual obligations are formed either directly or indirectly by this document. This
Group. 0120
document may not be reproduced or transmitted in any form or by any means,
electronic or mechanical, for any purpose, without our prior written permission. Disclaimer: This document is for informational purposes. It is not a commitment to deliver any
material, code, or functionality, and should not be relied upon in making purchasing decisions.
This device has not been authorized as required by the rules of the Federal
The development, release, timing, and pricing of any features or functionality described in this
Communications Commission. This device is not, and may not be, offered for sale or
document may change and remains at the sole discretion of Oracle Corporation.
lease, or sold or leased, until authorization is obtained.

26 Technical Brief / Application Programming Using Pooling and Caching / Version 1.0
Copyright © 2022, Oracle and/or its affiliates / Public

You might also like