SOLVED: Oracle XE: ORA-00821: Specified value of sga_target is too small

tl;dr

  • Open ${ORACLE_HOME}/assistants/dbca/templates/XE_Database.dbc with a text editor
  • Find <InitParamAttributes><InitParams>
  • Add the following XML tag under <InitParams>: <initParam name="cpu_count" value="2"/>

Background

If you are trying to run Oracle Database XE on a machine that has a lot of CPU cores (usually around 30+), you may come across this error during the database configuration phase:

[root@localhost ~]# /etc/init.d/oracle-xe-21c configure
Specify a password to be used for database accounts.
Oracle recommends that the password entered should be at least
8 characters in length, contain at least 1 uppercase character,
1 lower case character and 1 digit [0-9]. Note that the same
password will be used for SYS, SYSTEM and PDBADMIN accounts:
Confirm the password:
Configuring Oracle Listener.
Listener configuration succeeded.
Configuring Oracle Database XE.
Enter SYS user password:
***********
Enter SYSTEM user password:
************
Enter PDBADMIN User Password:
********
Prepare for db operation
7% complete
Copying database files
8% complete
[WARNING] ORA-00821: Specified value of sga_target 1536M is too small, needs to be at least 1600M
ORA-01078: failure in processing system parameters

9% complete
[FATAL] ORA-01034: ORACLE not available

29% complete
100% complete
[FATAL] ORA-01034: ORACLE not available

7% complete
0% complete
Look at the log file "/opt/oracle/cfgtoollogs/dbca/XE/XE.log" for further details.

Database configuration failed. Check logs under '/opt/oracle/cfgtoollogs/dbca'.

Note: the same can happen if your database runs inside a Docker container as the database looks at the CPUs of the host, not the CPU allocation of the container! See further details below.

Somehow the database determined that it needs more memory for SGA_TARGET than the default value. If you try to run this on really big machines (I’ve seen a case where the user tried to run this on a 128 CPU cores machine) you may find that the required memory will even exceed the allowed maximum of 2 GB for Oracle Database XE. But why do we even get this error? The culprit of all this is the CPU_COUNT parameter and its default value of 0, which enables dynamic sampling of the actual CPUs on the host machine:

If CPU_COUNT is set to 0 (its default setting), then Oracle Database continuously monitors the number of CPUs reported by the operating system and uses the current count. If CPU_COUNT is set to a value other than 0, then Oracle Database will use this count rather than the actual number of CPUs, thus disabling dynamic CPU reconfiguration.

Oracle Database 21c Documentation

This means that the database automatically determines the number of CPU cores on the machine and sets the value to that number. But why do CPU cores have any requirement on memory, that seems counter-intuitive, at first? Savvy Oracle Database users will know that many parameters derive their value from CPU_COUNT, such as DB_WRITER_PROCESSES, JOB_QUEUE_PROCESSES, PARALLEL_MAX_SERVERS, and more. Furthermore, the database does keep track of various CPU stats for the built-in resource manager and AWR/ASH diagnostics. All of these require at some point some memory to either do their job and process the information and hence a higher number of CPU_COUNT also means higher memory requirements.

All in all, that’s a good thing as the database makes sure to have enough memory to do its job rather than run out of memory during it. However, for Oracle Database XE all of that doesn’t make much sense really, as the max number of CPU cores that XE is ever going to use is set to 2. So why do all of this and calculate memory requirements that can even exceed the maximum memory for XE? Well, that’s a good point and you will be happy to hear that this has indeed already been identified as a bug by Oracle Development and will be fixed in the next release of XE. However, until then you may need a workaround. Luckily it’s rather simple.

Manually set CPU_COUNT=2

As the documentation above says, dynamic sampling of the CPU cores is only enabled when CPU_COUNT=0. So, the trick is to set CPU_COUNT=2 and the database will start up just fine again. To do so, however, a little bit of manual surgery is needed. The initial database parameters are all defined in the Database Configuration Assistant’s database template file, which you can find at ${ORACLE_HOME}/assistants/dbca/templates/XE_Database.dbc or /opt/oracle/product/21c/dbhomeXE/assistants/dbca/templates/XE_Database.dbc, if you like. You will notice that it’s just a plain XML file, so head in there with a text editor and find the <InitParamAttributes><InitParams> tag. There just add another one

<initParam name="cpu_count" value="2"/>

so that the whole section looks like this:

   <InitParamAttributes>
      <InitParams>
         <initParam name="cpu_count" value="2"/>
         <initParam name="db_name" value=""/>
         <initParam name="dispatchers" value="(PROTOCOL=TCP) (SERVICE={SID}XDB)"/>
         <initParam name="audit_file_dest" value="{ORACLE_BASE}/admin/{DB_UNIQUE_NAME}/adump"/>
         <initParam name="compatible" value="21.0.0"/>
         <initParam name="remote_login_passwordfile" value="EXCLUSIVE"/>
         <initParam name="sga_target" value="1536" unit="MB"/>
         <initParam name="undo_tablespace" value="UNDOTBS1"/>
         <initParam name="control_files" value="(&quot;{ORACLE_BASE}/oradata/{DB_UNIQUE_NAME}/control01.ctl&quot;, &quot;{ORACLE_BASE}/fast_recovery_area/{DB_UNIQUE_NAME}/control02.ctl&quot;)"/>
         <initParam name="diagnostic_dest" value="{ORACLE_BASE}"/>
         <initParam name="audit_trail" value="db"/>
         <initParam name="db_block_size" value="8" unit="KB"/>
         <initParam name="open_cursors" value="300"/>
         <initParam name="pga_aggregate_target" value="512" unit="MB"/>
      </InitParams>

Save the file and you are good to go and run /etc/init.d/oracle-xe-21c configure again:

[root@localhost templates]# /etc/init.d/oracle-xe-21c configure
Specify a password to be used for database accounts.
Oracle recommends that the password entered should be at least
8 characters in length, contain at least 1 uppercase character,
1 lower case character and 1 digit [0-9]. Note that the same
password will be used for SYS, SYSTEM and PDBADMIN accounts:
Confirm the password:
Configuring Oracle Listener.
Listener configuration succeeded.
Configuring Oracle Database XE.
Enter SYS user password:
***********
Enter SYSTEM user password:
*********
Enter PDBADMIN User Password:
**********
Prepare for db operation
7% complete
Copying database files
29% complete
Creating and starting Oracle instance
30% complete
33% complete
37% complete
40% complete
43% complete
Completing Database Creation
47% complete
Creating Pluggable Databases
54% complete
71% complete
Executing Post Configuration Actions
93% complete
Running Custom Scripts
100% complete
Database creation complete. For details check the logfiles at:
 /opt/oracle/cfgtoollogs/dbca/XE.
Database Information:
Global Database Name:XE
System Identifier(SID):XE
Look at the log file "/opt/oracle/cfgtoollogs/dbca/XE/XE2.log" for further details.

Connect to Oracle Database using one of the connect strings:
     Pluggable database: localhost.localdomain/XEPDB1
     Multitenant container database: localhost.localdomain
Use https://localhost:5500/em to access Oracle Enterprise Manager for Oracle Database XE

Misc

This workaround will work permanently. Once CPU_COUNT=2 is set, it will be persisted in the spfile and reused for every subsequent startup.

If you encounter this issue in other situations not necessarily during initial database creation, for example, you try to spin up a Docker container that already has a database configured or similar, you can still apply the same workaround. Essentially you need to get CPU_COUNT=2 into the spfile and everything will be good. One way to do this is to:

  1. connect to the shutdown database
  2. extract the spfile into a “pfile” text file
  3. add the parameter to that text file
  4. recreate the spfile

This looks like this (on the database server directly with the oracle user):

[oracle@localhost ~]$ sqlplus / as sysdba

SQL*Plus: Release 21.0.0.0.0 - Production on Fri Jun 10 16:19:03 2022
Version 21.3.0.0.0

Copyright (c) 1982, 2021, Oracle.  All rights reserved.

Connected to an idle instance.

SQL> create pfile='/tmp/pfile.ora' from spfile;

File created.

SQL> host echo "*.cpu_count=2" >> /tmp/pfile.ora

SQL> create spfile from pfile='/tmp/pfile.ora';

File created.

SQL> startup
ORACLE instance started.

Total System Global Area 1610612504 bytes
Fixed Size		    9690904 bytes
Variable Size		  637534208 bytes
Database Buffers	  956301312 bytes
Redo Buffers		    7086080 bytes
Database mounted.
Database opened.
SQL>

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.