CURSOR_SHARING - Reduce Hard Parsing by Sharing SQL Cursors
CURSOR_SHARING
Section titled “CURSOR_SHARING”Overview
Section titled “Overview”CURSOR_SHARING controls whether Oracle rewrites SQL statements that differ only in literal values to use system-generated bind variables, enabling those statements to share a single cursor in the shared pool. When set to EXACT (the default), Oracle only shares cursors for statements with identical SQL text. When set to FORCE, Oracle replaces literals (numbers, strings, dates) with bind variables before parsing, allowing many similar statements to share one cursor. This can dramatically reduce hard parsing, shared pool fragmentation, and latch contention — but introduces trade-offs around bind variable peeking and data skew.
Parameter Type: Dynamic (ALTER SESSION and ALTER SYSTEM) Default Value: EXACT Valid Values: EXACT, FORCE Deprecated Values: SIMILAR (removed in Oracle 12c) Available Since: Oracle 8.1.6 Modifiable: Yes — ALTER SESSION and ALTER SYSTEM PDB Modifiable: Yes
Configuration
Section titled “Configuration”Viewing Current Value
Section titled “Viewing Current Value”-- Current running valueSELECT name, value, descriptionFROM v$parameterWHERE name = 'cursor_sharing';
-- SPFILE valueSELECT name, valueFROM v$spparameterWHERE name = 'cursor_sharing';
-- Check related parameters togetherSELECT name, valueFROM v$parameterWHERE name IN ('cursor_sharing', 'open_cursors', 'session_cached_cursors', 'shared_pool_size')ORDER BY name;Setting the Parameter
Section titled “Setting the Parameter”-- Enable cursor sharing (system-wide)ALTER SYSTEM SET cursor_sharing = FORCE SCOPE = BOTH;
-- Revert to default (exact match only)ALTER SYSTEM SET cursor_sharing = EXACT SCOPE = BOTH;
-- Set for current session only (testing/tuning)ALTER SESSION SET cursor_sharing = FORCE;ALTER SESSION SET cursor_sharing = EXACT;
-- VerifySELECT name, value FROM v$parameter WHERE name = 'cursor_sharing';Tuning Guidance
Section titled “Tuning Guidance”When to Use FORCE
Section titled “When to Use FORCE”CURSOR_SHARING = FORCE is most beneficial when:
-
The application cannot be modified — legacy or third-party applications that embed literal values in SQL cannot be refactored to use bind variables.
FORCEprovides the benefit of bind variable sharing without code changes. -
High-volume OLTP with uniform data distribution — applications that execute thousands of similar
SELECT ... WHERE id = 12345statements per second create thousands of hard-parse events and consume shared pool memory. When the data distribution is uniform (similar row counts for each ID value), the plan generated for any given bind variable value is appropriate for all others, so plan quality does not suffer. -
Shared pool fragmentation is a documented problem — if the shared pool is filling with thousands of single-use SQL statements (identifiable via
V$SQL),FORCEcan reclaim that memory.
When to Avoid FORCE
Section titled “When to Avoid FORCE”CURSOR_SHARING = FORCE is dangerous when:
-
Data is skewed — if a
statuscolumn has 99% of rows with value'CLOSED'and 1% with'OPEN', the optimal plan forstatus = 'OPEN'(index scan) differs from the optimal plan forstatus = 'CLOSED'(full table scan). WithFORCE, both statements share one cursor with one plan — determined by which value was used when the cursor was first parsed (bind variable peeking). The wrong plan will be used for one of the values. -
The application already uses bind variables —
FORCEadds overhead for SQL rewriting with no benefit. -
Complex queries with multiple joins — cursor sharing can produce less optimal plans for complex analytical queries where literal values carry significant cardinality information.
-
Reporting or data warehouse workloads — these workloads typically issue unique queries anyway;
FORCEadds overhead without benefit.
Recommended Values
Section titled “Recommended Values”| Environment | Recommended Setting | Rationale |
|---|---|---|
| Well-written OLTP (uses bind variables) | EXACT (default) | No benefit from FORCE; avoid the overhead |
| Legacy OLTP with literal-heavy SQL | FORCE | Significant parse reduction if data is relatively uniform |
| Data warehouse / reporting | EXACT | Ad-hoc queries are unique; FORCE adds no benefit |
| Mixed (OLTP + reporting) | EXACT with session-level FORCE for OLTP sessions | Surgical application of cursor sharing |
| Applications with skewed data and literals | EXACT + bind variable refactoring | Fix the root cause; FORCE will cause plan quality issues |
Diagnosing Whether FORCE Would Help
Section titled “Diagnosing Whether FORCE Would Help”-- Find SQL statements with high version counts (many similar statements in the shared pool)-- High version counts with differing literals are the primary FORCE candidateSELECT sql_id, version_count, executions, parse_calls, ROUND(elapsed_time / 1e6, 2) AS elapsed_sec, SUBSTR(sql_text, 1, 100) AS sql_textFROM v$sqlareaWHERE version_count > 5ORDER BY version_count DESCFETCH FIRST 20 ROWS ONLY;
-- Find single-execution SQL statements (strong signal of literal-heavy applications)-- These are hard-parse candidates that FORCE would eliminateSELECT COUNT(*) AS single_exec_cursors, SUM(sharable_mem) / 1024 AS total_kb_wastedFROM v$sqlWHERE executions = 1 AND parse_calls = 1;
-- Quantify the shared pool impact of literal SQLSELECT ROUND(SUM(sharable_mem) / 1024 / 1024, 2) AS single_use_sql_mbFROM v$sqlWHERE executions = 1;
-- Hard parse rate (instance-wide since startup)SELECT name, valueFROM v$sysstatWHERE name IN ( 'parse count (total)', 'parse count (hard)', 'parse count (failures)')ORDER BY name;
-- Hard parse as a percentage of total parsesSELECT ROUND( (SELECT value FROM v$sysstat WHERE name = 'parse count (hard)') / NULLIF((SELECT value FROM v$sysstat WHERE name = 'parse count (total)'), 0) * 100, 2 ) AS hard_parse_pct;If hard_parse_pct exceeds 5–10% and single-execution SQL accounts for significant shared pool memory, CURSOR_SHARING = FORCE is worth evaluating.
Monitoring CURSOR_SHARING Effectiveness
Section titled “Monitoring CURSOR_SHARING Effectiveness”-- After enabling FORCE: check V$SQL_SHARED_CURSOR for reasons cursors cannot be shared-- This view explains why two similar statements ended up with separate cursorsSELECT sql_id, reasonFROM v$sql_shared_cursorWHERE ROWNUM <= 50;
-- Detailed shared cursor analysis — decode the bitmap columnSELECT c.sql_id, s.sql_text, c.unbound_cursor, c.optimizer_mismatch, c.optimizer_mode_mismatch, c.row_level_sec_mismatch, c.bind_mismatch, c.describe_mismatchFROM v$sql_shared_cursor cJOIN v$sql s ON s.sql_id = c.sql_idWHERE ROWNUM <= 20ORDER BY c.sql_id;
-- Compare hard parse rates before and after enabling FORCE-- Snapshot parse counts at two points in time to measure the rateSELECT name, value, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') AS snap_timeFROM v$sysstatWHERE name IN ('parse count (total)', 'parse count (hard)');
-- Monitor shared pool free memory to confirm reduction in fragmentationSELECT name, ROUND(bytes / 1024 / 1024, 2) AS mbFROM v$sgastatWHERE pool = 'shared pool' AND name IN ('free memory', 'library cache', 'sql area')ORDER BY name;
-- After enabling FORCE: verify version counts dropped for previously problematic SQLSELECT sql_id, version_count, executions, SUBSTR(sql_text, 1, 100) AS sql_textFROM v$sqlareaWHERE sql_id IN ('your_sql_id_1', 'your_sql_id_2') -- from pre-FORCE auditORDER BY version_count DESC;Common Issues
Section titled “Common Issues”Issue 1: Suboptimal Plans After Enabling CURSOR_SHARING = FORCE
Section titled “Issue 1: Suboptimal Plans After Enabling CURSOR_SHARING = FORCE”Symptom: Certain queries perform worse after enabling FORCE. A query that previously ran with an index range scan is now doing a full table scan, or vice versa.
Cause: Bind variable peeking. When Oracle first parses a statement under FORCE, it peeks at the current bind variable value and generates a plan optimised for that value. Subsequent executions with different values (particularly if data is skewed) reuse the same plan even if it is suboptimal for the new value.
Diagnosis and Resolution:
-- Check how many child cursors exist for the SQL (high count = plan instability)SELECT sql_id, child_number, plan_hash_value, executions, rows_processed, optimizer_modeFROM v$sqlWHERE sql_id = ':your_problem_sql_id'ORDER BY child_number;
-- View the actual execution plan for each child cursorSELECT *FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR( sql_id => ':your_problem_sql_id', child_number => 0, format => 'ALL'));
-- Option 1: Revert to EXACT for this session typeALTER SESSION SET cursor_sharing = EXACT;
-- Option 2: Refactor the application to use genuine bind variables-- and remove FORCE from the system configuration
-- Option 3: Use adaptive cursor sharing (ACS) — Oracle 11g+-- ACS automatically creates multiple child cursors for different bind value ranges-- Enabled by default when cursor_sharing = FORCE and optimizer_adaptive_cursor_sharing is TRUESELECT name, valueFROM v$parameterWHERE name IN ('_optimizer_adaptive_cursor_sharing', 'optimizer_adaptive_plans');Issue 2: SIMILAR Mode Found in Legacy SPFILE
Section titled “Issue 2: SIMILAR Mode Found in Legacy SPFILE”Symptom: After upgrading to 12c or later, the SPFILE contains cursor_sharing = SIMILAR, which is no longer a valid value.
Cause: SIMILAR was deprecated in Oracle 11g and removed in 12c. It was intended as a middle ground between EXACT and FORCE, but its behaviour was complex and it was rarely beneficial.
Resolution:
-- Check if SIMILAR is setSELECT name, value FROM v$parameter WHERE name = 'cursor_sharing';SELECT name, value FROM v$spparameter WHERE name = 'cursor_sharing';
-- Remove or replace the value-- Oracle 12c+ will treat SIMILAR as FORCE at startup (with a warning in the alert log)-- Explicitly set to EXACT or FORCE to remove ambiguityALTER SYSTEM SET cursor_sharing = EXACT SCOPE = BOTH;-- orALTER SYSTEM SET cursor_sharing = FORCE SCOPE = BOTH;Issue 3: Application Errors After Enabling FORCE
Section titled “Issue 3: Application Errors After Enabling FORCE”Symptom: After setting cursor_sharing = FORCE, some application queries return ORA-00932: inconsistent datatypes or unexpected results.
Cause: Oracle’s literal-to-bind-variable substitution under FORCE occasionally misidentifies the datatype of a literal, particularly with date literals, NVARCHAR comparisons, or strings that resemble numbers. The generated bind variable type does not match the column type.
Resolution:
-- Identify problematic SQL by looking for errors in V$SQLSELECT sql_id, executions, parse_calls, invalidations, SUBSTR(sql_text, 1, 100) AS sql_textFROM v$sqlWHERE sql_text LIKE '%:SYS_B_%' -- Oracle-generated bind variable names start with :SYS_B_ AND ROWNUM <= 20;
-- For problematic individual queries, add the NO_CURSOR_SHARING hintSELECT /*+ NO_CURSOR_SHARING */ order_id, order_dateFROM ordersWHERE status = 'OPEN';
-- Or revert cursor_sharing to EXACT system-wide and address hard parse issues-- through bind variable refactoring in the applicationALTER SYSTEM SET cursor_sharing = EXACT SCOPE = BOTH;Related Parameters
Section titled “Related Parameters”| Parameter | Relationship |
|---|---|
OPEN_CURSORS | Sets the maximum cursors per session. CURSOR_SHARING = FORCE reduces the number of distinct cursors in the shared pool, which reduces pressure on OPEN_CURSORS. |
SESSION_CACHED_CURSORS | Caches cursors in the session. Works synergistically with CURSOR_SHARING = FORCE — shared cursors can also be session-cached for soft-soft parses. |
OPTIMIZER_MODE | The optimizer’s goal applies to each shared cursor. Under FORCE, one plan serves all bind value variants; the optimizer mode determines whether that plan is throughput or first-rows oriented. |
OPTIMIZER_FEATURES_ENABLE | Adaptive cursor sharing (which mitigates some bind-peeking issues under FORCE) is gated by optimizer feature version. |
SHARED_POOL_SIZE | The primary benefit of CURSOR_SHARING = FORCE is reducing shared pool consumption from single-use SQL. Correctly sizing the shared pool reduces the urgency of enabling FORCE. |
Related Errors
Section titled “Related Errors”| Error | Description |
|---|---|
| ORA-00932 | Inconsistent datatypes — can be caused by CURSOR_SHARING = FORCE misidentifying literal types. |
| ORA-04031 | Unable to Allocate Shared Memory — the problem that CURSOR_SHARING = FORCE is often deployed to solve. Excessive hard parsing from literal-heavy SQL fragments the shared pool. |
Version Notes
Section titled “Version Notes”| Oracle Version | Notes |
|---|---|
| Oracle 8.1.6 | CURSOR_SHARING introduced. Valid values: EXACT, FORCE, SIMILAR. |
| Oracle 9i | SIMILAR mode added. FORCE widely recommended for legacy applications. |
| Oracle 10g | Adaptive cursor sharing groundwork laid. |
| Oracle 11g | SIMILAR deprecated. Adaptive Cursor Sharing (ACS) introduced to automatically create multiple child cursors under FORCE for skewed data. SIMILAR treated as FORCE. |
| Oracle 12c | SIMILAR value removed. Valid values are now only EXACT and FORCE. ACS is the recommended approach when FORCE is needed. |
| Oracle 19c | No change to valid values. FORCE continues to be appropriate for legacy OLTP applications that cannot be modified to use bind variables. |
| Oracle 23ai | No change. For new application development, genuine bind variables remain the recommended approach. FORCE is a retrofit solution for legacy code. |