大家好,这里是 Lucifer三思而后行,专注于提升数据库运维效率。


目录

  • 前言
  • 介绍
  • nomount 阶段
  • 参数文件
  • 分配 SGA
  • 启动进程
  • 总结


前言

作为一名 DBA,应该都玩过 Oracle 数据库,最熟悉的操作应该就是开关库了:

-- 开库
SQL> startup

-- 关库
SQL> shutdown immediate

但是执行这两个命令,数据库到底做了什么?相信很多人都没有研究过,本系列打算详解一下 Oracle 数据库的启动和关闭过程,静心看完,相信一定可以帮助大家更加深入了解 Oracle 数据库。

介绍

Oracle 数据库启动分为三个阶段:

  • nomount:读取参数文件,启动实例,分配 SGA,启动部分进程。
  • mount:实例启动后读取控制文件,挂载数据库。
  • open:读取数据文件和日志文件,启动数据库。

本文先讲数据库的第一个启动阶段:nomount 阶段,我这里演示环境是 11GR2 数据库。

nomount 阶段

nomount 阶段是数据库启动的第一个阶段,需要参数文件,会启动一个实例,在这个过程中会分配内存区域 SGA 以及启动一些后台进程。

参数文件

参数文件分为:

  • init<SID>.ora
  • spfile.ora
  • spfile<SID>.ora

单实例数据库存放在 $ORACLE_HOME/dbs 目录下,启动默认的查找顺序为:spfile<SID>.ora ---> spfile.ora ---> init<SID>.ora

可以发现当前数据库优先使用的是 spfile<SID>.ora 方式启动:

[oracle@rhel6:/home/oracle]$ cd $ORACLE_HOME/dbs
[oracle@rhel6:/u01/app/oracle/product/11.2.0/db/dbs]$ ll
-rw-rw----. 1 oracle oinstall    1544 Aug 26 22:57 hc_lucifer.dat
-rw-r--r--  1 oracle oinstall    2084 Jul 26 22:20 initlucifer.ora
-rw-r--r--. 1 oracle oinstall    2851 May 15  2009 init.ora
-rw-r-----. 1 oracle oinstall      24 Jul 10 18:43 lkLUCIFER
-rw-r-----. 1 oracle oinstall    1536 Aug 19 21:50 orapwlucifer
-rw-r-----  1 oracle oinstall 9781248 Aug 23 02:00 snapcf_lucifer.f
-rw-r-----. 1 oracle oinstall    5632 Aug 26 13:27 spfilelucifer.ora

验证一下,启动数据库实例:

-- 不指定参数文件,启动到 mnount 状态
SQL> startup nomount
ORACLE instance started.

Total System Global Area 4275781632 bytes
Fixed Size                  2260088 bytes
Variable Size            2801795976 bytes
Database Buffers         1459617792 bytes
Redo Buffers               12107776 bytes

-- 查看实例的状态为 STARTED
SQL> select status from v$instance;

STATUS
------------------------------------
STARTED

-- 查看 spfile 参数
SQL> show parameter spfile

NAME                                 TYPE                              VALUE
------------------------------------ --------------------------------- ------------------------------
spfile                               string                            /u01/app/oracle/product/11.2.0/db/dbs/spfilelucifer.ora

可以看到默认启动的参数文件是 spfilelucifer.ora,此时查看 alert 日志中参数文件相关的部分:

## 也可以看到是使用参数文件:/u01/app/oracle/product/11.2.0/db/dbs/spfilelucifer.ora,并且读取了参数文件中非系统默认的参数配置
Using parameter settings in server-side spfile /u01/app/oracle/product/11.2.0/db/dbs/spfilelucifer.ora
System parameters with non-default values:
  processes                = 2000
  resource_limit           = TRUE
  event                    = "28401 trace name context forever,level 1"
  event                    = "10949 trace name context forever,level 1"
  sga_max_size             = 4G
  streams_pool_size        = 1312M
  resource_manager_plan    = "force:"
  sga_target               = 4G
  _memory_imm_mode_without_autosga= FALSE
  control_files            = "/oradata/lucifer/control01.ctl"
  control_files            = "/u01/app/oracle/fast_recovery_area/lucifer/control02.ctl"
  control_file_record_keep_time= 31
  db_block_size            = 8192
  compatible               = "11.2.0.4.0"
  log_archive_dest_1       = "location=/oradata/archivelog"
  log_archive_format       = "%t_%s_%r.dbf"
  _use_adaptive_log_file_sync= "FALSE"
  db_files                 = 5000
  db_create_file_dest      = "/oradata"
  db_recovery_file_dest    = "/u01/app/oracle/fast_recovery_area"
  db_recovery_file_dest_size= 5532M
  enable_goldengate_replication= TRUE
  _datafile_write_errors_crash_instance= FALSE
  _cleanup_rollback_entries= 2000
  undo_tablespace          = "UNDOTBS1"
  _undo_autotune           = FALSE
  undo_retention           = 10800
  _partition_large_extents = "FALSE"
  _index_partition_large_extents= "FALSE"
  sec_case_sensitive_logon = FALSE
  remote_login_passwordfile= "EXCLUSIVE"
  db_domain                = ""
  dispatchers              = "(PROTOCOL=TCP) (SERVICE=luciferXDB)"
  session_cached_cursors   = 300
  parallel_max_servers     = 64
  _PX_use_large_pool       = TRUE
  audit_file_dest          = "/u01/app/oracle/admin/lucifer/adump"
  audit_trail              = "NONE"
  db_name                  = "lucifer"
  open_cursors             = 1000
  _optimizer_null_aware_antijoin= FALSE
  _b_tree_bitmap_plans     = FALSE
  _optimizer_extended_cursor_sharing= "NONE"
  _optimizer_extended_cursor_sharing_rel= "NONE"
  _optimizer_adaptive_cursor_sharing= FALSE
  pga_aggregate_target     = 1256M
  deferred_segment_creation= FALSE
  _optimizer_use_feedback  = FALSE
  enable_ddl_logging       = TRUE
  diagnostic_dest          = "/u01/app/oracle"

所以,数据库实例启动的第一步就是找到参数文件,并且读取参数配置。

分配 SGA

通过第一步读取参数文件配置,可以获取到内存相关配置,包括 SGA 相关参数:

sga_max_size             = 4G
streams_pool_size        = 1312M
sga_target               = 4G

在启动数据库实例过程中会输出以下信息:

Total System Global Area 4275781632 bytes
Fixed Size                  2260088 bytes
Variable Size            2801795976 bytes
Database Buffers         1459617792 bytes
Redo Buffers               12107776 bytes

以上这些提示信息分别是什么意思呢?大家如果知道 SGA 有哪些组件,应该一下就能明白:

参考 11GR2 官方文档 Database Concepts:Memory Architecture

Oracle 数据库启动过程之 nomount 详解_SQL

下面就详解一下启动数据库实例时输出的每一行的意思:

-- 这个是可分配的总 SGA 大小
Total System Global Area 4275781632 bytes

-- 可以通过查询 select sum(value) from v$sga; 或者 select sum(bytes) from v$sgastat; 
-- 注意:以上两个 SQL 在 11G 查询出来的结果值有出入,在 19C 查出来是一模一样 
-- 11GR2
SQL> select sum(value) from v$sga;

SUM(VALUE)
----------
4275781632

SQL> select sum(bytes) from v$sgastat;

SUM(BYTES)
----------
4275780728

-- 19C
SQL> select sum(value) from v$sga;

SUM(VALUE)
----------
5318374384

SQL> select sum(bytes) from v$sgastat;

SUM(BYTES)
----------
5318374384

-- Fixed SGA Size 包含数据库和实例的状态信息等通用信息,后台进程需要访问这部分信息,用于进程之间传递信息,不存储用户数据,大小由 Oracle 数据库设置,无法手动更改,大小可能会因版本而异。 
Fixed Size                  2260088 bytes

-- 可以通过查询 select * from v$sgainfo where name = 'Fixed SGA Size';
SQL> select * from v$sgainfo where name = 'Fixed SGA Size'; 

NAME                      BYTES RESIZEABL
-------------------- ---------- ---------
Fixed SGA Size          2260088 No

-- Variable size 包括 Shared Pool Size、Java Pool Size、Large Pool Size 和 Streams Pool Size。
Variable Size            2801795976 bytes

-- 可以通过查询 select * from v$sgainfo where name in ('Shared Pool Size','Java Pool Size','Large Pool Size','Streams Pool Size'); 

SQL> select * from v$sgainfo where name in ('Shared Pool Size','Java Pool Size','Large Pool Size','Streams Pool Size'); 

NAME                      BYTES RESIZEABL
-------------------- ---------- ---------
Shared Pool Size      587202560 Yes
Large Pool Size       805306368 Yes
Java Pool Size         33554432 Yes
Streams Pool Size    1375731712 Yes

-- 注意:这个 SQL 总和在 11G 查询出来的结果跟 Variable Size 的值有出入,在 19C 查出来是一模一样
SQL> select sum(bytes) from v$sgainfo where name in ('Shared Pool Size','Java Pool Size','Large Pool Size','Streams Pool Size'); 

SUM(BYTES)
----------
2801795072

-- Buffer Cache Size,数据库缓冲区缓存,也称为缓冲区高速缓存,是存储从数据文件读取的数据块副本的内存区域。
Database Buffers         1459617792 bytes

-- 可以通过查询 select * from v$sgainfo where name = 'Buffer Cache Size';
SQL> select * from v$sgainfo where name = 'Buffer Cache Size';

NAME                      BYTES RESIZEABL
-------------------- ---------- ---------
Buffer Cache Size    1459617792 Yes

-- Redo Buffers,重做日志缓冲区是 SGA 中的一个循环缓冲区,用于存储数据库所做更改的重做记录。
Redo Buffers               12107776 bytes

-- 可以通过查询 select * from v$sgainfo where name = 'Redo Buffers';
SQL> select * from v$sgainfo where name = 'Redo Buffers'; 

NAME                      BYTES RESIZEABL
-------------------- ---------- ---------
Redo Buffers           12107776 No

以上 SGA 组件内存分配的相关信息可以从 v$sgainfo 中查看:

SQL> select * from v$sgainfo;

NAME                                          BYTES RESIZEABL
---------------------------------------- ---------- ---------
Fixed SGA Size                              2260088 No
Redo Buffers                               12107776 No
Buffer Cache Size                        1459617792 Yes
Shared Pool Size                          587202560 Yes
Large Pool Size                           805306368 Yes
Java Pool Size                             33554432 Yes
Streams Pool Size                        1375731712 Yes
Shared IO Pool Size                               0 Yes
Granule Size                               16777216 No
Maximum SGA Size                         4275781632 No
Startup overhead in Shared Pool           498329672 No
Free SGA Memory Available                         0

这部分内容无法从 alert 日志中获取相关信息,所以直接打印在 sqlplus 启动过程中,也可以通过 show sga 查看:

SQL> show sga

Total System Global Area 4275781632 bytes
Fixed Size                  2260088 bytes
Variable Size            2801795976 bytes
Database Buffers         1459617792 bytes
Redo Buffers               12107776 bytes

上面是将数据库层面的 SGA 内存分配,其实在操作系统层面也可以看出个大概:

## 开启实例前
[oracle@rhel6:/home/oracle]$ ipcs -a

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 0          root       644        80         2                       
0x00000000 32769      root       644        16384      2                       
0x00000000 65538      root       644        280        2                 

## 可以看到,当数据库实例启动到 nomount 后,多了 3 个 oracle 用户的共享内存段
## nattch 表示当前附加到这个共享内存段的进程数
## oracle 用户 key 的值 0x00000000 的 bytes 之和为 4294967296,也就是 SGA 的大小为 4G,其中 33554432 代表的是 Java Pool Size,4261412864 是其他组件的总和。
[oracle@rhel6:/home/oracle]$ ipcs -m

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 0          root       644        80         2                       
0x00000000 32769      root       644        16384      2                       
0x00000000 65538      root       644        280        2                       
0x00000000 917507     oracle     640        33554432   17                      
0x00000000 950276     oracle     640        4261412864 17                      
0x467a6680 983045     oracle     640        2097152    17

注意:上面的输出中,关于共享内存段的列的意思如下:

key:共享内存段的键值,用于标识。
shmid:共享内存段的ID。
owner:共享内存段的所有者。
perms:共享内存段的权限,通常以4位八进制数表示。
bytes:共享内存段的大小,单位是字节。
nattch:当前附加到这个共享内存段的进程数。
status:共享内存段的状态,可能包含额外的信息或为空。

综上发现,数据库实例启动的第二步是分配 SGA 组件内存。

启动进程

查看进程启动情况:

-- 数据库实例启动前,没有 lucifer 实例相关的后台进程
SQL> ! env | grep ORACLE_SID
ORACLE_SID=lucifer

SQL> ! ps -ef|grep -v grep|grep lucifer

-- 数据库实例启动到 nomount 后,启动进程如下
SQL> ! ps -ef|grep -v grep|grep lucifer
-- 后台进程
oracle    57755      1  0 16:56 ?        00:00:00 ora_pmon_lucifer
oracle    57757      1  0 16:56 ?        00:00:00 ora_psp0_lucifer
oracle    57759      1  2 16:57 ?        00:00:40 ora_vktm_lucifer
oracle    57763      1  0 16:57 ?        00:00:00 ora_gen0_lucifer
oracle    57765      1  0 16:57 ?        00:00:00 ora_diag_lucifer
oracle    57767      1  0 16:57 ?        00:00:00 ora_dbrm_lucifer
oracle    57769      1  0 16:57 ?        00:00:06 ora_dia0_lucifer
oracle    57771      1  0 16:57 ?        00:00:00 ora_mman_lucifer
oracle    57773      1  0 16:57 ?        00:00:00 ora_dbw0_lucifer
oracle    57775      1  0 16:57 ?        00:00:00 ora_lgwr_lucifer
oracle    57777      1  0 16:57 ?        00:00:00 ora_ckpt_lucifer
oracle    57779      1  0 16:57 ?        00:00:00 ora_smon_lucifer
oracle    57781      1  0 16:57 ?        00:00:00 ora_reco_lucifer
oracle    57783      1  0 16:57 ?        00:00:00 ora_mmon_lucifer
oracle    57785      1  0 16:57 ?        00:00:03 ora_mmnl_lucifer
oracle    57787      1  0 16:57 ?        00:00:00 ora_d000_lucifer
oracle    57789      1  0 16:57 ?        00:00:00 ora_s000_lucifer
-- 前台进程,也就是当前连接的会话
oracle    61552  61551  0 17:29 ?        00:00:00 oraclelucifer (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))

-- 这里可以看到 ora_ 后台进程数为 17 个,与 ipcs -m 看到的 nattch 的数量相符
SQL> ! ps -ef|grep -v grep|grep ora_|wc -l
17

可以看到当 Oracle 启动到 nomount 状态后,有以下后台进程被启动:

  • pmon(Process Monitor):监视其他后台进程,并在服务器或调度程序进程异常终止时执行进程恢复。
  • psp0(Process Spawner Process):初始实例启动后生成 Oracle 后台进程。
  • vktm(Virtual Keeper of Time Process):提供一个秒级更新的数据库时钟,减少数据库和操作系统的交互。
  • gen0(General Task Execution Process):为数据库提供了一个执行通用任务的进程,进程的主要目标是分担进程中某些可能造成阻塞的处理过程,并将他们放在后台完成。
  • diag(Diagnostic Capture Process):数据库诊断进程,负责维护管理各种用于诊断的转储文件,并执行 oradebug 命令。
  • dbrm(Database Resource Manager Process):数据库资源管理进程,负责设置资源计划和其他的资源管理的工作。
  • dia0(Diagnostic Process):数据库诊断进程,负责检测 Oracle 数据库中的挂起(hang)和死锁的处理。
  • mman(Memory Manager Process):实现共享内存自动管理。
  • dbw0(Database Writer Process):数据库写入程序,主要职责是将数据块写入磁盘,还负责处理检查点、文件打开同步以及块写入记录的日志记录。
  • lgwr(Log Writer Process):日志写入程序,将重做日志条目按顺序写入重做日志文件。
  • ckpt(Checkpoint Process):在检查点处发出 DBWn 信号并更新数据库的所有数据文件和控制文件以指示最近的检查点。
  • smon(System Monitor Process):执行关键任务(如实例恢复和死事务恢复)以及维护任务(如临时空间回收、数据字典清理和撤消表空间管理)。
  • reco(Recoverer Process):解决由于分布式数据库中的网络或系统故障而挂起的分布式事务。
  • mmon(Manageability Monitor Process):MMON 执行许多与可管理性相关的任务,包括获取自动工作负载存储库快照和执行自动数据库诊断监视器分析。
  • mmnl(Manageability Monitor Lite Process):是 AWR 新增的进程,主要作用是将 AWR 数据从内存中刷新到表中。
  • d000(Dispatcher Process):允许用户进程共享有限的服务器进程(SERVER PROCESS)。
  • s000(Shared Server Process):负责与用户进程通信,并与 Oracle 交互,以代表相关的用户进程执行任务。

注意:以上后台进程具体可参考官方文档:Background Processes

查看数据库 alert 日志中与进程启动相关的信息:

## 启动后台进程,一共 17个
Mon Aug 26 16:56:59 2024
PMON started with pid=2, OS id=57755 
Mon Aug 26 16:56:59 2024
PSP0 started with pid=3, OS id=57757 
Mon Aug 26 16:57:00 2024
VKTM started with pid=4, OS id=57759 at elevated priority
VKTM running at (1)millisec precision with DBRM quantum (100)ms
Mon Aug 26 16:57:00 2024
GEN0 started with pid=5, OS id=57763 
Mon Aug 26 16:57:00 2024
DIAG started with pid=6, OS id=57765 
Mon Aug 26 16:57:00 2024
DBRM started with pid=7, OS id=57767 
Mon Aug 26 16:57:00 2024
DIA0 started with pid=8, OS id=57769 
Mon Aug 26 16:57:00 2024
MMAN started with pid=9, OS id=57771 
Mon Aug 26 16:57:00 2024
DBW0 started with pid=10, OS id=57773 
Mon Aug 26 16:57:00 2024
LGWR started with pid=11, OS id=57775 
Mon Aug 26 16:57:00 2024
CKPT started with pid=12, OS id=57777 
Mon Aug 26 16:57:00 2024
SMON started with pid=13, OS id=57779 
Mon Aug 26 16:57:00 2024
RECO started with pid=14, OS id=57781 
Mon Aug 26 16:57:00 2024
MMON started with pid=15, OS id=57783 
Mon Aug 26 16:57:00 2024
MMNL started with pid=16, OS id=57785

可以发现,数据库实例启动的第三步是启动进程。

总结

综上所述,可以总结出 nomount 阶段的启动过程大致如下:

  1. 查找参数文件,搜索顺序为:spfile<SID>.ora ---> spfile.ora ---> init<SID>.ora
  2. 读取参数文件,并启动数据库实例
  3. 分配 SGA 内存段
  4. 启动后台进程和前台进程

在这个阶段,不涉及控制文件以及数据文件,只需要参数文件即可,通常用于数据库创建、控制文件重建、特定的备份恢复等。


往期精彩文章推荐

Oracle RAC 修改系统时区避坑指南(深挖篇)Ubuntu 22.04 一键安装 Oracle 11G RAC使用 dbops 快速部署 MySQL 数据库Oracle RAC 启动顺序,你真的了解吗?达梦数据库一键安装脚本(免费)一篇文章让你彻底掌握 Python 🔥
一篇文章让你彻底掌握 Python一篇文章让你彻底掌握 Shell 🔥
Oracle 监控 EMCC 13.5 安装部署超详细教程 🔥
Oracle 一键巡检自动生成 Word 报告 🔥
Oracle一键安装脚本的 21 个疑问与解答 🔥
Oracle一键巡检脚本的 21 个疑问与解答 🔥
全网首发:Oracle 23ai 一键安装脚本 🔥
Oracle 19C 最新 RU 补丁 19.24 ,一键安装! 🔥
Oracle Linux 6 一键安装 Oracle 11GR2 RACOracle Linux 7.9 一键安装 Oracle 19COracle Linux 8.9 一键安装 Oracle 19C RACOracle Linux 9.4(aarch64) 一键安装 Oracle 19C 🔥
openEuler 20.03 LTS SP4 一键安装 Oracle 19C 🔥
openEuler 22.03 LTS SP4 一键安装 Oracle 19C RACRHEL 7.9 一键安装 Oracle 19C 19.23 RACRedhat 8.4 一键安装 Oracle 11GR2RedHat 9.4(aarch64) 一键安装 Oracle 19C龙蜥 Anolis 7.9 一键安装 Oracle 19C 19.23龙蜥 Anolis OS 8.8 一键安装 Oracle 19CSUSE 15 SP5 一键安装 Oracle 19C统信 UOS V20 1070(a) 一键安装 Oracle 11GR2Ubuntu 22.04 一键安装 Oracle 19CUbuntu 14.04 一键安装 Oracle 19C银河麒麟 Kylin V10 SP3 一键安装 Oracle 19C 🔥
银河麒麟 Kylin V10 SP3 一键安装 Oracle 11GR2 RACOracle DataGuard GAP 修复手册 🔥
优化 Oracle:最佳实践与开发规范DBA 必备:Linux 软件源配置全攻略 🔥
Linux 一键配置时钟同步全攻略 🔥
Starwind 配置 ISCSI 共享存储SUSE 15 SP3 安装 Oracle 19C RAC 数据库达梦 8 数据库安装手册 🔥
Oracle 12CR2 RAC 安装避坑宝典Linux7 安装 Oracle 19C RAC 详细图文教程 🔥
Oracle ADG 搭建 RAC to Single 详细教程Oracle DataGuard GAP 修复手册 🔥
Oracle 分区表之在线重定义AutoUpgrade 快速升级 Oracle 数据库Oracle 数据库巡检命令手册 🔥
Oracle 数据坏块的 N 种修复方式 🔥
数据库 SQL 开发入门教程超全 Linux 基础命令总结 🔥
VMware 虚拟机安装 Linux 系统Linux 安装 MySQL 详细教程教你玩转 SQLPLUS,工作效率提升 200%


感谢您的阅读,这里是 Lucifer三思而后行,欢迎 点赞+关注,我会持续分享数据库知识、运维技巧。