Lesson 11
Configuring Oracle Shared Server: Module Conclusion
Ten lessons ago, this module opened with a single observation: a dedicated server process per client connection is expensive at scale, and most of those processes spend most of their time doing nothing at all. Shared Server exists to fix that, and everything covered since, dispatchers, queues, sizing formulas, listener load balancing, connection pooling, and the monitoring views that tie it all together, has been working out the practical consequences of that one idea.
This conclusion walks back through the module lesson by lesson, then closes with a quick reference to the parameters and views you are most likely to reach for once this module is behind you, and a short list of the pitfalls that turned up more than once along the way, worth keeping in mind precisely because they were easy to miss the first time.
Building the Architecture: Lessons 1 and 2
Lesson 1 laid the architecture out end to end. Under Shared Server, a client never connects directly to a server process the way it does with a dedicated server; it connects to a dispatcher, which places the request on a single common queue shared by every dispatcher for that instance. Any idle shared server picks the next request off that queue, processes it, and places the response not back through the listener or the dispatcher that first received it, but onto that specific dispatcher's own response queue, one per dispatcher, in the SGA. The LREG background process keeps listeners updated with dispatcher location and load, which is what lets a listener hand off or redirect a connection to whichever dispatcher is currently least loaded. That architecture, Lesson 1 established, has been stable from Oracle Database 19c straight through to Oracle AI Database 26ai; what has changed around it is connection pooling technology, not the dispatcher and queue model itself.
Lesson 2 turned that architecture into actual configuration. The DISPATCHERS parameter carries a protocol address plus a set of optional attributes, CONNECTIONS, SESSIONS, LISTENER, MULTIPLEX, and SERVICE among them, and a sizing formula, the number of dispatchers equal to concurrent sessions divided by connections per dispatcher, rounded up, gives you a starting point rather than a guess. SHARED_SERVERS, MAX_SHARED_SERVERS, MAX_DISPATCHERS, CIRCUITS, and SHARED_SERVER_SESSIONS round out the parameter set, and every one of them, this lesson established and every lesson since confirmed, applies through ALTER SYSTEM without an instance restart, provided the instance is running from a server parameter file rather than a traditional PFILE.
What a Dispatcher Does, and Where Its Parameters Get Their Names: Lessons 3 and 4
Lesson 3 stepped back from syntax to explain function: a dispatcher manages traffic, it does not do database work itself, and the number you configure matters because too few means clients queue up waiting for a dispatcher before they ever reach a shared server, while too many wastes processes sitting mostly idle. This lesson also traced the module's parameters back to their pre-Oracle9i names, MTS_DISPATCHERS, MTS_SERVERS, MTS_MAX_SERVERS, and the rest, renamed wholesale when Multi-Threaded Server became Shared Server, a rename that reflected real added capability rather than being purely cosmetic.
Lesson 4 filled in what those two lessons left out: how Oracle actually decides how many shared servers to run at any given moment. PMON, not a static configuration value, starts additional shared servers up to MAX_SHARED_SERVERS as load demands and terminates idle ones back down toward the SHARED_SERVERS floor, typically stabilizing around one shared server per ten client connections, adjusted up or down based on how heavy each request actually is. This lesson also caught two operational details worth carrying forward: a database created with the Database Configuration Assistant may already show SHARED_SERVERS set to 1 purely to support Oracle XML DB, which is not the same as Shared Server being ready for your own application, and the listener genuinely needs to be running before the instance starts, since LREG's registration can otherwise be delayed by up to 60 seconds, a delay ALTER SYSTEM REGISTER can force past.
Load Balancing Across Listeners: Lesson 5
Lesson 5 extended the architecture across more than one listener, and was careful to keep two distinct mechanisms separate. Client side load balancing, LOAD_BALANCE=on paired with FAILOVER=on in a connect descriptor listing multiple addresses, is the client randomizing which listener it tries first. Server side connection load balancing is the listener that actually receives a request picking the least loaded node, then instance, then dispatcher to hand it to. Neither replaces the other, and the diagram this lesson walked through, a client connecting with SERVER=SHARED, LREG feeding listener load information, the listener selecting a dispatcher, and that dispatcher relaying requests through the common queue to the shared server pool and back through its own response queue, showed both mechanisms working together in a single connection's lifecycle.
Two Kinds of Pooling: Lessons 6 and 7
Lessons 6 and 7 introduced the module's one genuine departure from everything before it: Database Resident Connection Pooling is not Shared Server's dispatcher pool under another name. DRCP pools dedicated style servers through a separate background process, the connection broker, and works whether or not Shared Server is enabled on the instance at all. A client requesting a pooled connection stays persistently connected to the broker, gets handed a pooled server only while it actually has work to do, and returns that server to the pool the moment the work finishes, which is exactly the acquire-work-release cycle a typical web application produces thousands of times a minute. DBMS_CONNECTION_POOL.START_POOL(), MINSIZE, and MAXSIZE configure it; (SERVER=POOLED) in a connect descriptor is how a client actually asks for it, the same connect descriptor attribute Lesson 4 covered for (SERVER=DEDICATED) and this module covered throughout for the default Shared Server case.
Lesson 7's troubleshooting scenario is worth carrying forward as a general habit rather than a one-time fix: a configuration that looks entirely correct in every parameter and every ALTER SYSTEM statement can still do nothing at all if the client's own connect string was never updated to actually request it. Verifying that connections land where you configured them to, not just that the configuration itself is correct, is as much a part of enabling connection pooling as the configuration step itself.
Watching It Work: Lessons 8 Through 10
The module's final three lessons turned from configuration to observation. Lesson 8 built the monitoring toolkit: ps and netstat or ss at the operating system level for confirming processes and connections exist at all, and a family of dynamic performance views, V$QUEUE, V$DISPATCHER, V$DISPATCHER_RATE, V$SHARED_SERVER, V$CIRCUIT, and V$SHARED_SERVER_MONITOR, for what those processes are actually doing. Lessons 9 and 10 put that toolkit to work diagnosing contention specifically, and both converged on the same core lesson: a busy dispatcher and a busy shared server look similar from a distance but call for different fixes, and jumping straight from "this looks busy" to "add more of whatever this view is named after" is how you end up with plenty of capacity in the wrong place while the actual bottleneck goes unaddressed. Checking V$DISPATCHER's busy percentage, V$QUEUE's wait times by queue type, and V$SHARED_SERVER's own busy and idle figures together, in that order, before deciding what to change, is the discipline both lessons built toward.
Pitfalls Worth Remembering
A handful of specific traps surfaced more than once across this module, and they are worth listing together rather than leaving scattered across ten separate lessons.
- A nonzero
SHARED_SERVERS does not automatically mean Shared Server is ready for your application. A database created with DBCA can show SHARED_SERVERS = 1 purely to support Oracle XML DB, with no dispatcher covering ordinary SQL traffic at all, exactly the scenario Lessons 4 and 7 both walked through.
- The client side of a connection matters as much as the server side. A perfectly configured instance does nothing for a connect descriptor that never specifies
SERVER=SHARED or SERVER=POOLED in the first place, the single most common cause of "it's configured but not working" across Lessons 7 and 9.
- Pre-Oracle9i parameter names,
MTS_DISPATCHERS and its relatives, still turn up in older material and inherited parameter files. They map directly onto current names, covered in full in Lesson 3, but they do not work as-is on a current release.
- A PFILE is not deprecated, but it cannot be written to by
ALTER SYSTEM. Every dynamic parameter in this module needs a server parameter file for SCOPE=BOTH to actually persist a change, a detail that recurred from Lesson 2 onward.
- A busy dispatcher and a busy shared server are not the same problem, and treating them as interchangeable, adding dispatchers when shared servers were the actual constraint or the reverse, is how contention persists despite a configuration change that looked like it should have helped.
Quick Reference: Parameters
| Parameter | Purpose |
SHARED_SERVERS | Enables Shared Server; sets the initial, dynamically adjustable floor on shared server processes. |
MAX_SHARED_SERVERS | Ceiling PMON will grow the shared server pool to; no default, so unset means unconstrained. |
DISPATCHERS | Configures one or more dispatcher processes: protocol address plus attributes such as LISTENER and SERVICE. |
MAX_DISPATCHERS | Largely safe to leave alone today; reserved for a future auto-tuning feature. |
CIRCUITS | Caps total virtual circuits, inbound and outbound combined. |
SHARED_SERVER_SESSIONS | Caps concurrent shared server sessions, indirectly reserving capacity for dedicated connections. |
LISTENER_NETWORKS | General-purpose multi-network listener registration, not dispatcher-specific despite the name's proximity to this topic. |
Quick Reference: Monitoring Views
| View | Answers |
V$QUEUE | Queue depth and wait time, by TYPE: COMMON for the shared request queue, DISPATCHER for a dispatcher's response queue. |
V$DISPATCHER | Per-dispatcher busy and idle time, message and byte counts, current configuration via CONF_INDX. |
V$DISPATCHER_RATE | Current, average, and maximum dispatcher rate statistics for trend analysis over time. |
V$SHARED_SERVER | Per-shared-server status, busy and idle time, and total requests serviced. |
V$CIRCUIT | One specific connection's path through the architecture, down to which queue it is currently sitting on. |
V$SHARED_SERVER_MONITOR | Whether CIRCUITS, SHARED_SERVER_SESSIONS, or MAX_SHARED_SERVERS have ever actually been hit. |
V$SESSION | Which sessions are using Shared Server at all, filtered on SERVER = 'SHARED'. |
DBA_CPOOL_INFO / V$CPOOL_CONN_INFO | DRCP pool status and individual pooled connection state. |
If this module leaves you with one habit rather than one fact, it should be the instinct to check rather than assume: check what a parameter is actually configured for before trusting what it looks like it says, check the client side of a connection as readily as the server side, and check which specific view actually answers the question you are asking rather than reaching for whichever one happens to be most familiar. The architecture underneath all of it has proven stable for decades; the judgment about when and how to adjust it is what this module has been building toward all along.
That stability is worth dwelling on for a moment rather than passing over. A query against V$DISPATCHER written for an Oracle9i instance still runs, unmodified, against Oracle AI Database 26ai, which is not something you could say about most other corners of a database system over that same span. The parameters were renamed once, comprehensively, and have not moved since; the views and their columns have been even more stable than the parameters. What has genuinely changed across that same period is what sits alongside Shared Server rather than inside it, connection pooling chief among them, which is exactly why this module drew such a firm line between Lessons 1 through 5's architecture and Lessons 6 and 7's separate DRCP technology rather than treating them as one continuous topic.
Carrying that distinction forward is probably the single most useful thing to take from this module into the next one: not every technology that touches connections and scalability is Shared Server wearing a different name, and confusing the two, as a fair amount of the source material this module was built from originally did, is exactly how a correct individual fact ends up applied to the wrong architecture entirely.
Multithreaded Shared Servers - Quiz
