Sunday, September 27, 2026

Hidden Parameters in Oracle AI Database 26ai

 Tested on Oracle AI Database 26ai Enterprise Edition 23.26.3.0.0, connected to a PDB. Every list and count in this post was read from the live database. Oracle adds, renames, and removes hidden parameters in every release, so run the queries on your own version.

Companion post: Initialization Parameters in 26ai: Groups and Modify Levels, which explains the SESSION / SYSTEM / STATIC / PDB levels used below.

Warning: hidden parameters are undocumented and unsupported unless Oracle Support asks you to set one. Everything here is read-only exploration.

The appendix at the end has the complete list of all 7,076 hidden and 61 auto-maintained parameters, grouped by area, with type, value, level, PDB/RAC modifiability, and description.


What is a hidden parameter?

KindNameCount in 26aiWho sets it
Documentedname568You
Hidden_name7,076Oracle defaults. Change only on Oracle Support's advice
Auto-maintained__name61The instance itself
Total7,705

About 92% of all parameters are hidden (_), and another 61 (__) are records the instance keeps for itself. Hidden parameters don't show in V$PARAMETER unless someone has set them.


How to see them

X$ tables are only visible to SYS. Even with the DBA role and SELECT ANY DICTIONARY, a normal user gets:

SELECT COUNT(*) FROM x$ksppi;
ORA-00942: table or view "DONGHUA"."X$KSPPI" does not exist

As SYSDBA, join the name table (X$KSPPI) to the current value table (X$KSPPCV). The modify level comes from bit flags in KSPPIFLG. I took the bit decoding from Oracle's own definition of GV$PARAMETER:

SELECT view_definition FROM v$fixed_view_definition WHERE view_name = 'GV$PARAMETER';
-- ISSES_MODIFIABLE : BITAND(ksppiflg/256,1)        1 = TRUE
-- ISSYS_MODIFIABLE : BITAND(ksppiflg/65536,3)      1,3 = IMMEDIATE, 2 = DEFERRED, 0 = FALSE
-- ISPDB_MODIFIABLE : BITAND(ksppiflg/524288,1)     1 = TRUE

Full query: name, value, default flag, level, PDB flag, and description:

SELECT i.ksppinm  AS name,
       v.ksppstvl AS value,
       v.ksppstdf AS is_default,
       CASE WHEN BITAND(i.ksppiflg/256,1) = 1         THEN 'SESSION'
            WHEN BITAND(i.ksppiflg/65536,3) IN (1,3)  THEN 'SYSTEM_IMMEDIATE'
            WHEN BITAND(i.ksppiflg/65536,3) = 2       THEN 'SYSTEM_DEFERRED'
            ELSE 'STATIC' END                         AS lvl,
       DECODE(BITAND(i.ksppiflg/524288,1),1,'YES','NO') AS pdb_modifiable,
       i.ksppdesc AS description
FROM   x$ksppi  i
JOIN   x$ksppcv v ON i.indx = v.indx
WHERE  i.ksppinm LIKE '\_%' ESCAPE '\'
ORDER  BY i.ksppinm;

Use X$KSPPSV in place of X$KSPPCV for instance-level (system) values instead of session values.


Modify levels of hidden parameters

KindLevelCountPDB-modifiable
_ hiddenSESSION3,0192,776
_ hiddenSYSTEM (immediate)2,611605
_ hiddenSTATIC (spfile + restart)1,42651
_ hiddenSYSTEM (deferred)204
__ autoSYSTEM (immediate)548
__ autoSTATIC60
__ autoSESSION11

Hidden parameters are more likely than documented ones to be session-modifiable (43% vs 40%). That's because many of them are fine-grained optimizer and execution switches, which Oracle Support can have you test in a single session.


Hidden parameters grouped by area

Oracle doesn't store a category, and the name prefix alone is noisy: there are 1,142 distinct first words, many of them generic like _enable_, _disable_, _max_. So I mapped names into areas with patterns (for example, _lm*, _gc*, _ges* → RAC). The grouping is my own, and 3,929 (55%) don't match a pattern and stay in "Other".

Area (name patterns)TotalSESSIONSYSTEM imm.SYSTEM def.STATICPDB-mod
RAC / cluster (_lm, _gc, _gcs, _gcr, _ges, _lms, _ksxp, _ksipc, …)69916385029828
Optimizer / cursor (optim, _unnest, _hash_join, _nlj, _cursor, _bloom, …)3813482418355
In-Memory (_inmemory, _imcs, …)25591142022179
Diagnostics / monitoring (_diag, _hang, _sqlmon, _trace, _ash, _awr, …)2553917604047
ASM (_asm)2399112761512
OLAP / analytic views (_hcs, _olap, _xsolapi)206193904195
Memory / buffer cache (_shared_pool, _kgh, _kgl, _pga, _sga, _db_block, …)183199506937
Parallel execution (_px, _parallel)17114117013139
AI Vector Search (_vector)1711194804161
LOB / compression (_kdli, _lob, _kdz)989800097
Multitenant (_pdb, _cdb)95651701371
Redo / recovery (_log, _lgwr, _redo, _recovery, …)913530356
Exadata smart scan (_kcfis, _cell)888500385
AQ / replication (_aq, _bufq, _streams, _xstream, …)683510149
Backup / restore (_backup, _restore, _rman)574771248
Undo / flashback (_undo, _smu, _rollback, _flashback)5753202013
Data Guard (_dg, _standby, _adg)33127052
Other3,9291,6551,401128611,952

What the table shows:

  • RAC / cluster is the largest named group (699), and it's almost entirely instance-wide: SYSTEM or STATIC, with only 16 SESSION. Cluster messaging and lock management can't differ per session.
  • Optimizer: 348 of 381 are SESSION and 355 are PDB-modifiable. This is the one area where a hidden parameter can be tested in a single session, for example with ALTER SESSION or the OPT_PARAM hint.
  • AI Vector Search already has 171 hidden parameters, which shows how much internal tuning surface the newest 26ai feature has.
  • Redo / recovery and Undo are mostly SYSTEM or STATIC and rarely PDB-modifiable. They belong to the CDB's shared redo and undo layer.
  • Exadata smart scan has 88 parameters even on this non-Exadata install. The parameters exist in every build whether or not the hardware is present.

The query I used:

WITH hp AS (
  SELECT i.ksppinm name,
    CASE
     WHEN REGEXP_LIKE(i.ksppinm,'^_(lm|gc|gcs|gcr|ges|lms|ksxp|ksipc|rac|ipc|cgs|kjdd|dlm|imr)(_|$)') THEN 'RAC / cluster'
     WHEN REGEXP_LIKE(i.ksppinm,'^_asm') THEN 'ASM'
     WHEN REGEXP_LIKE(i.ksppinm,'^_(kcfis|cell)') THEN 'Exadata smart scan'
     WHEN REGEXP_LIKE(i.ksppinm,'^_(inmemory|imado|imcs|imu)') THEN 'In-Memory'
     WHEN REGEXP_LIKE(i.ksppinm,'^_vector') THEN 'AI Vector Search'
     WHEN REGEXP_LIKE(i.ksppinm,'^_(px|parallel)') THEN 'Parallel execution'
     WHEN REGEXP_LIKE(i.ksppinm,'(optim|_unnest|_hash_join|_index_join|_nlj|_like_|_cursor|_bloom|_complex_view|_push_|_gby|_query_rewrite|_cost)') THEN 'Optimizer / cursor'
     WHEN REGEXP_LIKE(i.ksppinm,'^_(pdb|cdb)') THEN 'Multitenant (PDB/CDB)'
     WHEN REGEXP_LIKE(i.ksppinm,'^_(hcs|olap|xsolapi)') THEN 'OLAP / analytic views'
     WHEN REGEXP_LIKE(i.ksppinm,'^_(kdli|lob|kdz)') THEN 'LOB / compression'
     WHEN REGEXP_LIKE(i.ksppinm,'^_(aq|bufq|streams|xstream|goldengate)') THEN 'AQ / replication'
     WHEN REGEXP_LIKE(i.ksppinm,'^_(log|lgwr|redo|recovery|rcv|fast_start|instance_recovery)') THEN 'Redo / recovery'
     WHEN REGEXP_LIKE(i.ksppinm,'^_(backup|restore|rman)') THEN 'Backup / restore'
     WHEN REGEXP_LIKE(i.ksppinm,'^_(undo|smu|rollback|flashback)') THEN 'Undo / flashback'
     WHEN REGEXP_LIKE(i.ksppinm,'^_(shared_pool|kgh|kgl|pga|sga|memory|mem|large_pool|db_cache|buffer|db_block)') THEN 'Memory / buffer cache'
     WHEN REGEXP_LIKE(i.ksppinm,'^_(diag|hang|sqlmon|trace|dump|ash|awr|kse|dbg)') THEN 'Diagnostics / monitoring'
     WHEN REGEXP_LIKE(i.ksppinm,'^_(dg|dataguard|standby|adg)') THEN 'Data Guard'
     ELSE 'Other' END area,
    CASE WHEN BITAND(i.ksppiflg/256,1)=1 THEN 'SESSION'
         WHEN BITAND(i.ksppiflg/65536,3) IN (1,3) THEN 'SYSTEM_IMMEDIATE'
         WHEN BITAND(i.ksppiflg/65536,3)=2 THEN 'SYSTEM_DEFERRED'
         ELSE 'STATIC' END lvl,
    BITAND(i.ksppiflg/524288,1) pdb
  FROM x$ksppi i
  WHERE i.ksppinm LIKE '\_%' ESCAPE '\' AND i.ksppinm NOT LIKE '\_\_%' ESCAPE '\')
SELECT area, COUNT(*) total,
       SUM(DECODE(lvl,'SESSION',1,0))          ses,
       SUM(DECODE(lvl,'SYSTEM_IMMEDIATE',1,0)) sys_imm,
       SUM(DECODE(lvl,'SYSTEM_DEFERRED',1,0))  sys_def,
       SUM(DECODE(lvl,'STATIC',1,0))           static,
       SUM(pdb)                                pdb_mod
FROM hp GROUP BY area ORDER BY total DESC;

Which hidden parameters are actually set here?

Filter on KSPPSTDF = 'FALSE':

NameValueLevelPDB-mod
__db_cache_size1811939328SYSTEM (immediate)NO
__shared_pool_size905969664SYSTEM (immediate)NO
__java_pool_size251658240SYSTEM (immediate)NO
__large_pool_size16777216SYSTEM (immediate)NO
__shared_io_pool_size134217728SYSTEM (immediate)NO
__sga_target3154116608STATICNO
__pga_aggregate_target1056964608SYSTEM (immediate)NO
__oracle_base/u01/app/oracleSTATICNO
__data_transfer_cache_size, __datamemory_area_size, __inmemory_ext_roarea, __inmemory_ext_rwarea, __streams_pool_size, __unified_pga_pool_size0SYSTEM (immediate)NO
_instance_recovery_bloom_filter_size1048576SYSTEM (immediate)NO

None of these can be changed at PDB level. They're all instance-wide memory and environment settings owned by the CDB.

  • The __ parameters are the instance recording the current sizes chosen by automatic memory management (about 1.7 GB buffer cache and 864 MB shared pool), persisted in the spfile so the next startup begins from the same place. Nobody "set" these, and you leave them alone.
  • Only one _ parameter is explicitly set: _instance_recovery_bloom_filter_size. Everything else in this database runs on defaults, which is how it should be.

Hidden parameters behind plan behavior

These are the switches behind behavior I tested in my plan statistics notes. All of them are SESSION level and PDB-modifiable in 26ai:

ParameterValueControlsSeen in the plan notes
_optim_peek_user_bindsTRUEBind peekingSame SQL: full scan for 'NAME_0', index scan for 'NAME_5'
_optimizer_adaptive_cursor_sharingTRUEDifferent plans per bind value
_optimizer_extended_cursor_sharingUDOExtended cursor sharing
_optimizer_extended_cursor_sharing_relSIMPLESame, for relational operators
_nlj_batching_enabled1Nested loop batchingThe two stacked NESTED LOOPS lines
_optimizer_batch_table_access_by_rowidTRUERowid batchingTABLE ACCESS BY INDEX ROWID BATCHED
_unnest_subqueryTRUESubquery unnestingNeeded NO_UNNEST to force the slow correlated subquery
_index_join_enabledTRUEIndex joinsVIEW index$_join$_001
_hash_join_enabledTRUEHash joins
_optimizer_skip_scan_enabledTRUEIndex skip scan
_optimizer_use_feedbackTRUEStatistics feedback
_like_with_bind_as_equalityFALSETreat LIKE :b as =
_optimizer_gather_stats_on_conventional_dmlFALSEReal-time stats during DMLStale num_rows after inserting 90K rows
_optimizer_use_stats_on_conventional_dmlFALSEUse those real-time stats
_optimizer_cost_modelCHOOSECost model selection
_sqlmon_threshold5Seconds before automatic SQL MonitorNeeded /*+ MONITOR */ for a 0.0004s query
_sqlmon_max_planlines1000Longest plan SQL Monitor will trackThe talk's 213-line plan fits

Real-time statistics is shown as FALSE here. Oracle enables that feature only on Exadata and Oracle Cloud platforms, so it's off on this on-premises install.


Prefer the supported ways of changing behavior

Instead of setting…Use
_optim_peek_user_bindsHistograms, adaptive cursor sharing, SQL plan baselines
_unnest_subqueryUNNEST / NO_UNNEST hints
_optimizer_batch_table_access_by_rowidBATCH_TABLE_ACCESS_BY_ROWID / NO_BATCH_... hints
_hash_join_enabled, _index_join_enabledUSE_HASH, NO_USE_HASH, INDEX_JOIN hints
_sqlmon_thresholdMONITOR / NO_MONITOR hints

If Oracle Support does ask you to test one, use the narrowest scope its level allows. For a SESSION-level parameter, that's a single statement with OPT_PARAM:

SELECT /*+ OPT_PARAM('_optimizer_skip_scan_enabled' 'false') */ ...

or ALTER SESSION. Use ALTER SYSTEM only if it's needed, with the SR number recorded. STATIC ones need the spfile and a restart, so plan them as a change window.


Takeaways

  • 26ai has 7,076 hidden _ parameters plus 61 __ auto-maintained ones, against 568 documented.
  • You need SYS to see them. The modify level is encoded in X$KSPPI.KSPPIFLG, and GV$PARAMETER's own view definition shows how to decode it.
  • RAC is the largest named group and is instance-wide. Optimizer is the most session-friendly group (91% SESSION level).
  • A healthy database has very few _ parameters set. This one has one. Checking for non-default hidden parameters is a good first step after inheriting a database or upgrading.
  • Because the list changes every release, re-run the queries on your version rather than copying lists from blogs, including this one.

SQLPlus gotcha I hit while writing this: a line ending in -, such as PROMPT --- title ---, is treated as a continuation character, so the next SQL line gets swallowed into the prompt. Don't end SQLPlus lines with a hyphen.