Every failed Oracle installation traces back to the same place: a system that was not ready. The database is famously particular about its host -- kernel parameters, users and groups, directory ownership, resource limits. Get the preparation right and the installer is boring. Get it wrong and you will meet error messages written in 1998.
This part prepares AlmaLinux 9 to receive Oracle Database 26ai: the packages, the kernel and limits configuration, the oracle user and its groups, and the directory layout the rest of the series builds on. Done once, done right, never revisited.
Phase 1 - OS tuning
Oracle Database leans on specific kernel settings to run correctly and efficiently. They control how much shared memory Oracle may allocate for its SGA, how many file descriptors a process may open, how async I/O behaves, and how aggressively the kernel reclaims and swaps memory. Get them wrong and either the install refuses to proceed or performance suffers badly. Everything in this phase is permanent across reboots.
Kernel parameters
These go in /etc/sysctl.d/97-oracle.conf. A few are worth calling out. kernel.shmmax is the largest shared memory segment Oracle can allocate - set to 6 GB on this 8 GB server. fs.aio-max-nr caps async I/O requests, which Oracle relies on for direct I/O. vm.swappiness = 10 tells the kernel to avoid swapping, keeping the Oracle SGA resident in RAM rather than paged out to disk.
# Shared memory
kernel.shmmax = 6442450944
kernel.shmall = 1572864
kernel.shmmni = 4096
kernel.sem = 250 32000 100 128
# Async I/O
fs.aio-max-nr = 1048576
fs.file-max = 6815744
# Network buffers
net.core.rmem_max = 4194304
net.core.wmem_max = 4194304
net.ipv4.tcp_rmem = 4096 87380 4194304
net.ipv4.tcp_wmem = 4096 65536 4194304
# VM - reduce swapping, keep Oracle in RAM
vm.swappiness = 10
vm.dirty_background_ratio = 3
vm.dirty_ratio = 15
sysctl -p /etc/sysctl.d/97-oracle.conf
The final sysctl -p line loads the file so the settings take effect without a reboot. kernel.shmmax at 6442450944 is exactly 6 GB in bytes - this is one of the values to revisit if your server is not an 8 GB box.
User limits
The Oracle account also needs raised resource limits. These go in /etc/security/limits.d/99-oracle.conf. nofile sets how many files the oracle user may open at once - Oracle juggles datafiles, redo logs, and trace files simultaneously, and the Linux default is far too low. memlock = unlimited lets Oracle lock SGA pages into RAM so they can never be swapped out.
oracle soft nofile 65536
oracle hard nofile 65536
oracle soft nproc 16384
oracle hard nproc 16384
oracle soft stack 10240
oracle hard stack 32768
oracle soft memlock unlimited
oracle hard memlock unlimited
Disable Transparent Huge Pages
Transparent Huge Pages (THP) is a Linux memory feature that, on a database host, does more harm than good: as the kernel tries to defragment memory into large pages, Oracle sees latency spikes. Oracle's standing recommendation is to disable it explicitly.
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
These two commands turn THP off for the running system. To make the change survive reboots, you would also set it through the bootloader or a boot-time service - the guide shows the runtime commands.
Phase 2 - Database parameter tuning
A fresh Oracle install is deliberately conservative. It does not know how much memory your server has, so it allocates little. We tell it. The two big pools are the SGA (System Global Area, the shared cache all sessions use) and the PGA (Program Global Area, per-session working memory). On this 8 GB server the split is roughly 4.5 GB to the SGA, 1.5 GB to the PGA, leaving about 2 GB for the OS and everything else.
Two clauses appear throughout. SCOPE=SPFILE writes the change to the server parameter file so it survives a restart but does not apply until then. SCOPE=BOTH applies the change immediately and saves it to the SPFILE. The memory parameters here are SPFILE-only because they take effect when the database is restarted after this phase.
Memory parameters
Connect as sysdba to the CDB and apply the memory settings.
ALTER SYSTEM SET sga_max_size = 4608M SCOPE=SPFILE;
ALTER SYSTEM SET sga_target = 4608M SCOPE=SPFILE;
ALTER SYSTEM SET db_cache_size = 2048M SCOPE=SPFILE;
ALTER SYSTEM SET shared_pool_size = 1280M SCOPE=SPFILE;
ALTER SYSTEM SET large_pool_size = 256M SCOPE=SPFILE;
ALTER SYSTEM SET java_pool_size = 256M SCOPE=SPFILE;
ALTER SYSTEM SET streams_pool_size = 128M SCOPE=SPFILE;
ALTER SYSTEM SET pga_aggregate_target = 1536M SCOPE=SPFILE;
ALTER SYSTEM SET pga_aggregate_limit = 3072M SCOPE=SPFILE;
ALTER SYSTEM SET workarea_size_policy = AUTO SCOPE=SPFILE;
Every one of these is sized for 8 GB of RAM. sga_max_size and sga_target at 4608M (4.5 GB), pga_aggregate_target at 1536M (1.5 GB) - if you are on different hardware, these are the numbers to rescale. Keep the same proportions and leave headroom for the OS.
Processes, cursors, and I/O
The next group sizes how many sessions the database supports and how it does I/O. processes and sessions cap concurrency. filesystemio_options = SETALL enables both direct I/O and async I/O. Note that open_cursors, fast_start_mttr_target, and optimizer_adaptive_statistics use SCOPE=BOTH, so they apply at once.
ALTER SYSTEM SET processes = 500 SCOPE=SPFILE;
ALTER SYSTEM SET sessions = 555 SCOPE=SPFILE;
ALTER SYSTEM SET open_cursors = 1000 SCOPE=BOTH;
ALTER SYSTEM SET session_cached_cursors = 100 SCOPE=SPFILE;
ALTER SYSTEM SET filesystemio_options = SETALL SCOPE=SPFILE;
ALTER SYSTEM SET log_buffer = 33554432 SCOPE=SPFILE;
ALTER SYSTEM SET fast_start_mttr_target = 60 SCOPE=BOTH;
ALTER SYSTEM SET optimizer_adaptive_statistics = TRUE SCOPE=BOTH;
Resize the redo logs - 200 MB to 500 MB
The database ships with three 200 MB redo log groups. Small redo logs switch often, and every log switch triggers a checkpoint and a burst of I/O. An APEX workload is full of small, frequent transactions, so those switches add up. Moving to four 500 MB groups cuts the switch and checkpoint frequency and smooths out write performance.
You cannot shrink a log group in place, so the technique is to add the new larger groups, force the old ones to become inactive with a couple of log switches and a checkpoint, then drop them.
-- Add 4 new groups at 500MB
ALTER DATABASE ADD LOGFILE GROUP 4 '/opt/oracle/oradata/ORCLCDB/redo04.log' SIZE 500M;
ALTER DATABASE ADD LOGFILE GROUP 5 '/opt/oracle/oradata/ORCLCDB/redo05.log' SIZE 500M;
ALTER DATABASE ADD LOGFILE GROUP 6 '/opt/oracle/oradata/ORCLCDB/redo06.log' SIZE 500M;
ALTER DATABASE ADD LOGFILE GROUP 7 '/opt/oracle/oradata/ORCLCDB/redo07.log' SIZE 500M;
-- Switch logs to make old groups inactive, then drop them
ALTER SYSTEM SWITCH LOGFILE;
ALTER SYSTEM CHECKPOINT;
ALTER DATABASE DROP LOGFILE GROUP 1;
ALTER DATABASE DROP LOGFILE GROUP 2;
ALTER DATABASE DROP LOGFILE GROUP 3;
A group must be inactive before you can drop it. If a DROP LOGFILE GROUP complains that the group is active or current, issue another ALTER SYSTEM SWITCH LOGFILE; and checkpoint, then retry. The datafile paths under /opt/oracle/oradata/ORCLCDB/ assume the placeholder Oracle base - adjust them to your own layout.
With the memory and process parameters set to SPFILE, restart the database so they take effect. The redo changes above are already live.
What you have now: an AlmaLinux 9 host tuned for Oracle - kernel parameters, raised limits, THP disabled - and an Oracle 26ai database sized for 8 GB of RAM with larger redo logs. The foundation is stable. Next, in Tutorial 02, we carve out a dedicated pluggable database, APEX_PDB, with its own tablespaces and install the APEX 26.1 engine into it.