一、题目相关
1. 英文题目和英语选项和答案
Question #17, Topic 1
Which two statements are true regarding Oracle database space management within blocks managed by Automatic Segment Space Management (ASSM)? (Choose two.)
Options:
- A. PCTFREE defaults to 10% for all blocks in all segments for all compression methods
- B. ASSM assigns blocks to one of four fullness categories based on what percentage of the block is allocated for rows
- C. Update operations always attempt to find blocks with free space appropriate to the length of the row being updated
- D. Insert operations always attempt to find blocks with free space appropriate to the length of the row being inserted
- E. A block will always be eligible for inserts if the row is short enough to fit into the block
Correct Answer: B, D
2. 题目和选项的翻译,答案
题干翻译:
关于由自动段空间管理(ASSM)所管理的数据块内的空间管理 ,下面哪两个陈述是正确的?(选两个)
选项翻译:
- A. 对于所有压缩方法下的所有段中的所有块,PCTFREE 的默认值都是 10%。
- B. ASSM 会根据"块中已经分配给行的空间所占的百分比",把块划分成四个"充满度"类别之一。
- C. UPDATE(更新)操作总是会去查找"空闲空间刚好能容纳被更新行长度"的块。
- D. INSERT(插入)操作总是会去查找"空闲空间刚好能容纳被插入行长度"的块。
- E. 只要某行足够短、能塞进某个块 ,那个块就一定可以被用来插入。
答案:B、D
💡 一句话剧透:B 是 ASSM 的核心机制(四档 fullness,靠位图管理),D 是 ASSM 插入的寻块策略(按整行长度找合适的块,避免行链接)。A(压缩表 PCTFREE 默认是 0 不是 10)、C(UPDATE 优先原地更新,不是总去找新块)、E(低于 PCTFREE 阈值的块拒绝插入,哪怕塞得下)都是陷阱。
3. 考察的知识点摘要
| 序号 | 知识点 | 一句话理解 |
|---|---|---|
| 1 | ASSM(自动段空间管理) | 用**位图(bitmap)**管空闲空间,取代老式 freelist |
| 2 | 四种 fullness 类别 | FS1(0-25%)、FS2(25-50%)、FS3(50-75%)、FS4(75-100%) |
| 3 | PCTFREE 默认值与压缩 | 普通表默认 10%,基础压缩(BASIC)默认 0% |
| 4 | INSERT 寻块策略 | 按整行长度找"够大"的块,避免行链接(row chaining) |
| 5 | UPDATE 的行为 | 优先在原块更新;空间不够才考虑迁移(row migration) |
| 6 | PCTFREE 阈值 | 空闲 ≤ PCTFREE 的块被标"满",拒绝新插入 |
4. 题目解析
🔹 B. ASSM 把块分为四个充满度类别 ------ ✅ 正确
这是 ASSM 的招牌机制。每个数据块的块头用位图记录"还有多少空闲空间",据此分成四档(再加"未格式化"和"逻辑满"):
- FS1:0%~25% 空闲
- FS2:25%~50% 空闲
- FS3:50%~75% 空闲
- FS4:75%~100% 空闲
插入时 Oracle 靠这套分类快速定位 合适的块,不用像老 freelist 那样挨个试。所以 B 对。
🔹 D. INSERT 总是按行长找合适的空闲块 ------ ✅ 正确
这是 ASSM 相比传统管理的一大优势:插入前会比对"整行的实际长度"和"块的可用空间" ,专门挑一个能完整装下整行 的块,目的就是避免行链接(row chaining) ,让一行尽量待在一个块里。所以 D 对。
🔹 A. PCTFREE 对所有压缩方法都默认 10% ------ ❌ 错误
"all compression methods"这个绝对化表述是致命伤。事实是:普通(NOCOMPRESS / OLTP 压缩)表 PCTFREE 默认 10%,但 BASIC 基础压缩表默认是 0% (官方文档原文:"Tables with COMPRESS or COMPRESS BASIC use a PCTFREE value of 0" )。所以"都是 10%"不成立,A 错。
🔹 C. UPDATE 总是去找合适大小的块 ------ ❌ 错误
关键词是"always(总是) "。UPDATE 的逻辑是:能原地放下就原地更新 ,只有当修改后的行变长、当前块实在塞不下时,才会发生**行迁移(row migration)**去找新块。"总是主动去找新块"完全不符合实际,C 错。
🔹 E. 只要行塞得下,块就一定可插入 ------ ❌ 错误
又是"always "惹的祸。Oracle 判断是否接受插入看的是 PCTFREE 阈值 :一旦块的空闲降到 PCTFREE(如 10%)及以下 ,该块就被标记为"满(full)",只接受 UPDATE/DELETE,拒绝新的 INSERT ------哪怕某个短行理论上塞得下。所以 E 错。
⚠️ 本题的"坑位密码" :三个错误选项 A/C/E 全都栽在绝对化用词上------A 的 "all"、C 的 "always"、E 的 "always"。考试时看到这些词要本能警惕,而 B、D 描述的是 ASSM 真实、稳定的行为。
5. 考察的知识点详情
下面用 Oracle 实操例子逐个击破,帮你把 ASSM 这套"自动空间管理"彻底玩明白。以普通用户(如 HR)登录即可。
1️⃣ 确认表用的是 ASSM(对应 B 的前提)
ASSM 是在表空间级别设置的:
sql
SELECT tablespace_name, segment_space_management
FROM dba_tablespaces
WHERE tablespace_name = 'USERS';
-- SEGMENT_SPACE_MANAGEMENT = AUTO 表示 ASSM
2️⃣ 四种 fullness 类别(对应选项 B)
sql
-- 用 DBMS_SPACE 查看某个段的块分布(FS1~FS4)
DECLARE
l_fs1 NUMBER; l_fs2 NUMBER; l_fs3 NUMBER; l_fs4 NUMBER; l_full NUMBER;
BEGIN
dbms_space.space_usage(
segment_owner => 'HR', segment_name => 'EMPLOYEES', segment_type => 'TABLE',
fs1_blocks => l_fs1, fs2_blocks => l_fs2, fs3_blocks => l_fs3,
fs4_blocks => l_fs4, full_blocks => l_full);
dbms_output.put_line('FS1(0-25% free): ' || l_fs1);
dbms_output.put_line('FS2(25-50% free): ' || l_fs2);
dbms_output.put_line('FS3(50-75% free): ' || l_fs3);
dbms_output.put_line('FS4(75-100% free): ' || l_fs4);
END;
/
📌 输出的 FS1~FS4 正好印证 B:块按空闲百分比被归入四个类别,ASSM 据此分配新行。
3️⃣ PCTFREE 与压缩的关系(对应选项 A,反例)
sql
CREATE TABLE t_normal (c1 VARCHAR2(100)); -- 普通表
SELECT pct_free FROM user_tables WHERE table_name = 'T_NORMAL'; -- 10
CREATE TABLE t_compress (c1 VARCHAR2(100)) ROW STORE COMPRESS BASIC; -- 基础压缩
SELECT pct_free FROM user_tables WHERE table_name = 'T_COMPRESS'; -- 0 ← A被打脸
📌 官方原文:"For a table with basic compression, PCTFREE defaults to 0." 所以 A 的"all = 10%"错误。
4️⃣ INSERT 按行长找合适块(对应选项 D)
sql
CREATE TABLE t_assm (id NUMBER, pad VARCHAR2(4000)) PCTFREE 10;
-- 短行:塞进 FS4(还很空)的块
INSERT INTO t_assm SELECT rownum, lpad('x',10,'x') FROM dual CONNECT BY rownum <= 1000;
-- 长行:专门找 FS1/FS2(空间充足)的块,避免一行横跨两个块
INSERT INTO t_assm SELECT rownum+1000, lpad('x',3000,'x') FROM dual CONNECT BY rownum <= 100;
COMMIT;
📌 这就是 D 的正确行为:插入前比对整行长度与块空闲空间,优先保证"一行一个块"。
5️⃣ UPDATE 优先原地更新(对应选项 C,反例)
sql
UPDATE t_assm SET pad = lpad('x',50,'x') WHERE id = 1; -- 多在原块完成
COMMIT;
📌 只有改长后超出当前块剩余空间 ,才会触发行迁移(row migration)------把整行搬到新块、原处留"转发地址"。绝不是"每次 UPDATE 都主动去找新块",所以 C 的 "always" 不成立。
6️⃣ PCTFREE 阈值导致"塞得下也不让插"(对应选项 E,反例)
sql
CREATE TABLE t_pct (c1 CHAR(1000)) PCTFREE 10;
BEGIN
FOR i IN 1..1000 LOOP INSERT INTO t_pct VALUES ('row ' || i); END LOOP;
END;
/
-- 此时该块空闲已 ≤10%,被 ASSM 标记为"满"
-- 哪怕下面这行极短(几个字节),也会被拒之门外、转向其他块
INSERT INTO t_pct VALUES ('tiny');
📌 现实中这行"转到别的块成功了",但绝不会塞进那个已满的块 ------证明 E 的"always eligible"错误:低于 PCTFREE 的块只服务 UPDATE/DELETE,不接新 INSERT。
7️⃣ 几个 DBA 必记的"坑"
- 🔴 ASSM vs MSSM :
SEGMENT_SPACE_MANAGEMENT = AUTO是 ASSM(默认,用位图),MANUAL是老式 freelist。ASSM 里 PCTUSED 参数被忽略,只有 PCTFREE 有效。 - 🔴 **在线段收缩(shrink)**要求 ASSM + 本地管理表空间。
- 🟡
DBMS_SPACE.SPACE_USAGE是观察 ASSM 块分布的利器,排查行链接、空间碎片常用。 - 🟡 **行链接(chaining)**多 → 检查是否该调大 PCTFREE 或块大小;**行迁移(migration)**多 → 往往和压缩表 PCTFREE=0 有关(update 压缩行导致)。
ASSM知识点详解
参考文章
https://blog.csdn.net/u014596132/article/details/135645353
这张对照图把「一次 INSERT 怎么找块」在两种机制下各走了一遍:
左图 MSSM(手动段管理)
- 插入 → 查 Freelist → 判断「该块在不在列表上」(二值)
- 块的空间变化靠两个阈值驱动:PCTFREE (占用满到这个点 → 摘出列表)、PCTUSED(DELETE 后回到这个点 → 重新挂回,即「复活点」)
- 本质是 一个 PCTUSED 阈值决定让不让插
右图 ASSM(自动段管理)
- 插入 → 扫位图 → 按行大小挑对应空闲档位的块
- 位图给每块标 4 档 :
>75% / 50%-75% / 25%-50% / <25% - 块始终在位图里,档位随空间增减连续滑动 ;没有「复活」概念,PCTUSED 被忽略,只剩 PCTFREE 生效
箭头旁标了「4 档状态替代 PCTUSED」,正是你说的核心:把单阈值二值判断,升级成按剩余空间档位选块。

表中一行数据都放在一个数据块中吗?满了咋办?不是把每个值存到数据块中吗?而是每一行为单位放到数据块中吗?
图已生成。下面按你的三个问题逐条对上。
先给结论
对,你理解得基本正确:以「行」为单位组织,一行的所有普通列值尽可能放在同一个数据块里。
- 不是「把每个列值单独挑一个块存」,而是「整行 的各列值打包放进一个块」。
- 每个列值的确存在块里 ------ 但它们因为是同一行,所以落在同一块的同一片行空间里。
为什么「以行为单位」
- 磁盘和内存的最小读写单位就是块(8K/16K 等),一行的列紧挨着存,读整行只要读一个块,最快。
- 块内有行目录(row directory),记录「第 N 行从哪个字节偏移开始」,所以定位一行 = 定位块 + 块内偏移。
「满了咋办」------ 这正是右图的三种情况
① 超长列 / LOB:溢出段(Overflow / LOB Segment)
- 行所在的块里只留一个定位符(LOB locator),真正的超长数据放在专门的 LOB 段、可以跨很多块。
- 原则不变:短小的普通列仍挤在同一块,只是巨型列单独安置。
② 行太长,一个块根本塞不下:行链接(Row Chaining)
- 一行 > 块容量(比如行总长 > 块大小),拆成两段:块 M 放前半 + 指针,块 N 放后半,甚至串更多块。
- 这是插入时就发生的,属于「被迫跨块」。
③ UPDATE 变长,原块塞不下了:行迁移(Row Migration)
- 原本一行好好待在块 A,UPDATE 后行变大,A 已满 → Oracle 把整行搬 到另一个有空位的块 B,原位置只留一个转发指针。
- 代价:读这行要多访问一个块。这正好呼应上一轮的位图档位 / PCTFREE ------ PCTFREE 就是提前留白来减少行迁移的。
串起来一句话
默认「一行 = 一个块内的一片连续空间」;只有超长列(溢出)、行超大(链接)、更新膨胀(迁移)这三种「满了/放不下」的情况,才会让一行跨块。 选块的过程,就是上一轮说的:MSSM 查 Freelist、ASSM 看位图四档空闲率。
