参数有两份:内存里一份(马上生效、重启就没了),spfile 里一份(重启才生效、一直在)。
SCOPE 就是用来选改哪一份的。
改参数最常见的两个事故:改了 SCOPE=MEMORY 重启后「白改了」,和改错了没法回退。
所以这一篇的重点不是语法,是「改完怎么确认」。
第 13 章讲的是「别出错」。 从这一篇开始讲「跑得快」—— 调优的第一步永远是「把参数调对」,因为参数错了,后面怎么优化 SQL 都白费。 这一篇是第 14 章的地基: 14.2 讲 SGA 的几块内存怎么分,14.3 讲排序区怎么调,而「怎么改」这件事只在这一篇讲一次。
一、先分清两类参数
| 分类 | 例子 | 能不能改 |
|---|---|---|
| 初始化参数 | SGA_TARGET、PROCESSES |
可以,看是否静态 |
| 隐藏参数 | _lm_dd_interval |
能改,但别碰 |
隐藏参数名字以下划线开头,官方文档里查不到。
它们是给 Oracle 自己用的,改错了可能起不来,而且升级后行为会变。
只有一种情况值得碰:官方支持明确让你临时设一个来绕过 bug。
初始化参数还能再分两类,这个分类更实用:
「动态参数」改完立刻生效,「静态参数」只能写进 spfile、重启才生效。
DB_BLOCK_SIZE、DB_NAME、SGA_MAX_SIZE 都是静态的。
二、pfile 和 spfile:一个文本、一个二进制
| pfile | spfile | |
|---|---|---|
| 形式 | 文本,能拿记事本改 | 二进制,只能 ALTER SYSTEM 改 |
| 默认名 | init<sid>.ora |
spfile<sid>.ora |
| 位置 | $ORACLE_HOME/dbs |
$ORACLE_HOME/dbs |
| 谁优先 | 两个都在时,spfile 优先 | —— |
spfile 优先,这是 9i 之后的行为。
所以「我改了 pfile 怎么不生效」的答案通常是:目录里还有个 spfile,它把你的 pfile 盖住了。
spfile 的好处是「不会写错语法」——文本文件里多一个空格、少一个引号,实例可能就起不来。
spfile 由数据库自己维护,格式永远是对的。
坏处是「出问题时改不动」——
起不来的实例没法执行 ALTER SYSTEM,只能先用 pfile 起来,再重建 spfile。
三、SCOPE 三个值,选错就白改
SCOPE= |
内存 | spfile | 什么时候用 |
|---|---|---|---|
MEMORY |
改 | 不改 | 临时试一下 |
SPFILE |
不改 | 改 | 静态参数只能这么改 |
BOTH(默认) |
改 | 改 | 常规改法 |
默认是 BOTH,所以大多数时候你什么都不用写。
但有两个例外必须显式写:
一是静态参数(写 BOTH 会报 ORA-02095,只能写 SPFILE),
二是「只想临时试试」(写 MEMORY)。
注意 SCOPE=MEMORY 的坑:改完当时是好的,重启就回去了。
而且它不写警告,你就这么忘了。
所以生产上要养成习惯:改完立刻 SHOW PARAMETER 看一眼,
再查一次 V$SPPARAMETER 确认磁盘上也改了。
一个看内存,一个看文件,两个都对上才算改完。
四、主要参数:先记住这七个
| 参数 | 管什么 | 怎么定 |
|---|---|---|
SGA_TARGET |
SGA 总大小,自动分给各池 | 物理内存的一半左右 |
PGA_AGGREGATE_TARGET |
所有会话的排序、哈希内存总和 | 物理内存的 20% 上下 |
DB_CACHE_SIZE |
缓冲池(放数据块) | 设 0 交给自动管理 |
SHARED_POOL_SIZE |
共享池(放 SQL 和字典) | 设 0 交给自动管理 |
LOG_BUFFER |
日志缓冲区 | 几兆到几十兆,别大 |
PROCESSES |
最大进程数(连带着 SESSIONS) |
按连接数上限留余量 |
OPEN_CURSORS |
一个会话最多开几个游标 | 默认 300,一般够 |
前两个是总闸,后面两个(DB_CACHE_SIZE、SHARED_POOL_SIZE)建议留 0。
留 0 不是「不分配」,是「交给 SGA_TARGET 自动分」——这叫自动共享内存管理(ASMM)。
手动指定这两个数,等于把自动分配关掉一部分,通常没必要。
PROCESSES 有个连带关系要知道:改它,SESSIONS 会按 1.1 倍自动跟着调。
反过来只改 SESSIONS 也行,但两边不一致的时候可能报 ORA-00020。
所以连接数不够,改 PROCESSES。
五、改参数的规矩:四条
一、一次只改一个,改完观察。
同时改五个,出问题了你不知道是哪个引起的。
二、改之前把原值记下来。
SHOW PARAMETER 的结果存一份,回退的时候照着改回去。
ALTER SYSTEM RESET 能回默认值,但默认值随版本变,不是你想要的那个旧值。
三、挑时间改。
改 SGA_TARGET 会导致内存重新分配,短时间性能会抖一下。
改 PROCESSES 要重启。
这类操作别在大促当天做。
四、改完写进变更记录。
「谁在什么时候把 SGA_TARGET 从 2G 改成 4G、为什么」——半年后有人问起,只有记录能回答。
参数漂移是运维里最难查的一类问题:没人记得改过,但行为就是和文档不一样。
六、动手 Demo:两份参数值,一次重启,看清 SCOPE 的作用
参数管理这件事没法在 SQLite 上验,所以这一篇的 Demo 是一个手写的参数文件模型。
它照着 Oracle 的规矩来:磁盘一份、内存一份,SCOPE 决定改哪份,静态参数只让写文件。
模型的输出就是每一次「内存值 vs 磁盘值」的对照表。
看懂这张表,SCOPE 就不会再用错。
# 参数文件模型:内存一份、磁盘一份
import os, tempfile
P = os.path.join(tempfile.gettempdir(), "spfile47.ora")
class ParamFile(object):
STATIC = ("db_block_size", "db_name", "sga_max_size")
def __init__(self, path):
self.path = path
self.spfile = {"sga_target": "2G", "processes": "300",
"db_block_size": "8K"}
self.mem = {}
self.flush()
def flush(self): # 写磁盘
with open(self.path, "w") as f:
for k in sorted(self.spfile):
f.write("%s=%s\n" % (k, self.spfile[k]))
def startup(self): # 启动:读磁盘进内存
self.mem = {}
with open(self.path) as f:
for ln in f:
k, v = ln.strip().split("=", 1)
self.mem[k] = v
def alter(self, name, value, scope="BOTH"):
if name in self.STATIC and scope != "SPFILE":
return "ORA-02095: 无法修改指定的初始化参数"
if scope in ("BOTH", "MEMORY"):
self.mem[name] = value
if scope in ("BOTH", "SPFILE"):
self.spfile[name] = value
self.flush()
return "系统已更改"
db = ParamFile(P)
db.startup()
print(db.alter("sga_target", "4G", "MEMORY"))
print("内存", db.mem["sga_target"], "磁盘", db.spfile["sga_target"])
db.startup() # 重启
print("重启后内存", db.mem["sga_target"]) # 回到 2G
实跑输出:
--------------------------------------------------------------------
第六十一课:参数文件——内存一份,磁盘一份
--------------------------------------------------------------------
**改参数这件事最容易搞错的不是语法,是「改哪一份」。**
**内存有一份(马上生效、重启就没),磁盘有一份(重启后才生效、但一直留着)。**
**这一课把这两份的差别用一个能真跑的模型摆清楚。**
一、启动的时候读的是 spfile
--------------------------------------------------------------------
**实例启动:把 spfile 里的键值读进内存。**
参数 内存值 SPFILE 值
-------------------------------------
sga_target 2G 2G
pga_aggregate_target 512M 512M
db_cache_size 0 0
shared_pool_size 0 0
已选择 4 行
**两份完全一样,因为它们就是一次拷贝。**
**从这里开始,两份就可能分叉了。**
二、SCOPE=MEMORY:只管这一会儿
--------------------------------------------------------------------
`ALTER SYSTEM SET sga_target=4G SCOPE=MEMORY;` 返回:系统已更改
参数 内存值 SPFILE 值
---------------------------
sga_target 4G 2G
已选择 1 行
**内存里是 4G,磁盘上还是 2G。**
**这意味着「当前跑得欢,重启就回去」——**
**临时试一试的时候用它,试完记得改回去。**
三、重启一次,看看丢了什么
--------------------------------------------------------------------
参数 内存值 SPFILE 值
---------------------------
sga_target 2G 2G
已选择 1 行
**果然回到 2G。**
**所以「我明明改过了,怎么又变回去了」这个问题,答案永远是「你只改了内存」。**
四、SCOPE=SPFILE:现在不动,重启才动
--------------------------------------------------------------------
`ALTER SYSTEM SET processes=600 SCOPE=SPFILE;` 返回:系统已更改
参数 内存值 SPFILE 值
--------------------------
processes 300 600
已选择 1 行
**内存里还是 300,磁盘上已经 600。**
**改完这句、重启之前,新连接还是按 300 算。**
**`PROCESSES` 这类参数不是「动态」的,只能这么改。**
参数 内存值 SPFILE 值
--------------------------
processes 600 600
已选择 1 行
**重启之后 600 生效了。**
五、静态参数:连 SCOPE=BOTH 都不让用
--------------------------------------------------------------------
`ALTER SYSTEM SET db_block_size=16K;` 返回:ORA-02095: 无法修改指定的初始化参数
带上 `SCOPE=SPFILE` 再试:系统已更改
**注意第二句「成功」只是写进了文件。**
**不重启,数据库还是 8K 的块。**
**`DB_BLOCK_SIZE` 是建库时定死的,理论上改 spfile 也没用**——
**它只在建库那一刻生效,之后改它就是「自欺欺人」。**
六、改错了想回去:RESET
--------------------------------------------------------------------
动作 内存值 SPFILE 值
----------------------------------------------
改之前 300 600
ALTER SYSTEM RESET processes 300 (默认值)
已选择 2 行
**`ALTER SYSTEM RESET processes;` 把参数从 spfile 里删掉,回到默认值。**
**比手写一个「默认值」更稳**——**因为默认值随版本会变,你写死的那个数未必还是默认。**
**这一课一共把 spfile 重写了 4 次(算上建文件那一次)。**
**每改一个参数,整个文件都要重写一遍,所以别把它写成循环。**
第一段:启动时两份一样。
这不是巧合,实例启动就是「把文件读进内存」。
第二段:SCOPE=MEMORY 之后,内存 4G、磁盘 2G。
这一行是整篇最该记住的:改完当时是有效的,重启就回到 2G。
第三段:重启验证。
「我明明改过」这句话,九成出在这一步。
第四段:SCOPE=SPFILE 反过来——内存还是 300,磁盘已经 600。
这句改完、重启之前,新连接还是按 300 算。
所以「改完没反应」也可能是对的,只是还没重启。
第五段:静态参数写 BOTH 报 ORA-02095,写 SPFILE 才通过。
注意这个「通过」只是写进了文件,DB_BLOCK_SIZE 实际上建库时就定死了,改它没有意义。
第六段:RESET 是回默认值,不是回旧值。
想回旧值只有一个办法:改之前记下来。
30 秒实验
- 给模型加一个
scope=u"INVALID"的分支,让它报ORA-02065(非法选项)。 想想真库里这个错一般是怎么来的。 - 在模型里把
processes也加进STATIC,再跑一遍。 你会看到SCOPE=BOTH直接被拒——这就是静态参数的待遇。 - 把
flush()换成「追加写一行」而不是「重写整个文件」,再数一数写文件的次数。 真 spfile 是整块重写的,这也是「别批量改参数」的原因。
常见误区
- 「改完
SHOW PARAMETER是新的就好了」。 不一定。 那个命令看的是内存值。要确认磁盘,得查V$SPPARAMETER。 - 「spfile 能用文本编辑器改」。 不能,它是二进制。
要改只能
ALTER SYSTEM,或者先导成 pfile 改完再导回去。 - 「参数越大越快」。 反例很多:
LOG_BUFFER大了提交变慢,SORT_AREA_SIZE大了几十个会话一起来就 OOM。 - 「隐藏参数调一调性能就上去了」。 大多数时候是「调完看着快了,其实别的地方坏了」。 除非官方文档或补丁说明明确让你设,否则别动。
自测三问(点开对答案)
1. `SCOPE=MEMORY` 和 `SCOPE=SPFILE` 分别改哪里? —— **前者只改内存(重启丢失),后者只改文件(重启生效)。** **`BOTH` 是两边都改,也是默认值。** 2. 静态参数为什么不能写 `SCOPE=BOTH`? —— **因为内存里改不了**,只能写进文件等重启,所以会报 `ORA-02095`。 3. 改完参数怎么确认真的改上了? —— **两个地方都看:`SHOW PARAMETER` 看内存,`V$SPPARAMETER` 看文件。** 4. pfile 和 spfile 同时在,用哪个? —— **spfile 优先。** 想让 pfile 生效,得先把 spfile 挪走或者改名。下一篇讲 SGA。参数是「怎么改」,SGA 是「改什么」。
这一篇的表里 SGA_TARGET 排第一,下一篇就把这块内存拆开看:缓冲池、共享池、
日志缓冲区各占多少、各管什么。
- ☐ (本篇完,下一篇 14.2 系统全局区(SGA)优化)
相关笔记
- 逻辑存储结构
- 设置 SQL*Plus 的运行环境
-
- 🐬 MySQL必知必会/00-索引
- 🏺 Oracle从入门到精通 · 索引