Oracle数据库段管理那些事儿,技巧和经验聊聊再说
- 问答
- 2026-01-17 10:49:16
- 4
说到Oracle数据库的段管理,这其实是每个DBA日常工作中都会打交道,但又容易忽略其底层细节的部分,你可以把数据库想象成一个巨大的仓库,段就是这个仓库里一个个具体的“储物单元”,比如表、索引这些,都是段,管理好这些储物单元,仓库才能井井有条,存取高效,我今天聊的,主要就是基于Oracle官方文档和一些老DBA的实践经验,说说这里面的门道。
得搞清楚段、区和块的关系。
这是理解段管理的基础,根据Oracle的概念,数据库的存储结构是这么层层下来的:表空间 -> 段 -> 区 -> 数据块,表空间是最大的逻辑存储单位,好比仓库本身,段是位于表空间内的独立存储结构,就是仓库里的一个个货架,比如一张表对应一个表段,一个索引对应一个索引段,区是段中一组连续的数据块,相当于货架上的一格,数据块是Oracle管理存储的最小单位,也是I/O操作的最小单位,就像格子里放东西的最小空间,一个段是由一个或多个区组成的,当段创建时,它会分配一个初始区,当段中的空间用完时,Oracle会自动为它分配新的区,管理段,很大程度上就是在管理这些区的分配和回收。
重点聊聊两种主流的段空间管理方式:MSSM和ASSM。
这是Oracle发展史上的一个重要分水岭,在早期的版本里,Oracle使用一种叫做手动段空间管理(MSSM) 的方式,这种方式下,段内部的空间使用情况,比如哪些数据块还有空闲空间,这些空闲空间有多少,都是由一个叫“空闲列表”的数据结构来记录的,DBA在创建表或者索引的时候,需要手动设置一些参数,比如FREELISTS(设置有几个空闲列表)和PCTUSED(设置块使用率达到多少以下时,这个块才会被重新放回空闲列表,允许插入新数据),这种方式问题很多,就像老式的仓库管理,需要人工记账,非常依赖DBA的经验,如果FREELISTS设置得太小,在高并发插入时,多个会话会争抢同一个空闲列表,产生严重的等待;如果PCTUSED设置不合理,会导致数据块的空间利用率低下,或者碎片化严重,管理起来非常麻烦。
后来,从Oracle 9i开始,引入了自动段空间管理(ASSM),这可以说是一个解放DBA的伟大发明,ASSM彻底抛弃了手工管理的空闲列表和PCTUSED参数,它使用一种“位图”的方式来管理段内的空间,你可以把它想象成给仓库的每个小格子(数据块)都装上了红绿灯,位图中的每一位都对应一个数据块,并通过不同的状态值来标记这个块的空间使用情况,满的”、“有75%空闲”、“有50%空闲”等,当需要插入新数据时,Oracle会自动去寻找那些处于合适空闲状态的块,完全不用DBA操心,ASSM的好处是显而易见的:极大简化了管理,减少了DBA的错误配置,更重要的是,它能显著减少高并发插入时的段头块争用,现在除非有极其特殊的兼容性要求,否则都应该使用ASSM,在创建表空间时,指定SEGMENT SPACE MANAGEMENT AUTO就是开启了ASSM。

说说高水位线的问题,这是段管理的一个核心痛点。
每个段都有一个“高水位线”,你可以把它想象成仓库货架上的一个标记,这个标记以下的数据块,表示都曾经被使用过(哪怕现在里面的数据被删除了,块是空的);标记以上的块,是从来没有被格式化使用过的“处女地”,当全表扫描时,Oracle会读取高水位线以下的所有块,即使这些块是空的,这就带来了一个经典问题:如果一张表曾经有10G数据,然后你用DELETE语句删掉了9.9G,表里实际数据只剩100M了,但它的高水位线依然在10G的位置,这时候你对这张表做全表扫描,Oracle仍然会去读取那10G的空间,I/O性能会非常差。
怎么解决高水位线问题呢?常用的技巧有几个。

最直接有效的方法是使用TRUNCATE TABLE命令。TRUNCATE会直接重置高水位线,相当于把货架上的标记直接拉回到起点,并且立即释放空间,但它的缺点是DDL操作,不能回滚,而且会触发表上所有索引的重建,另一个方法是ALTER TABLE ... SHRINK SPACE,这个命令是在ASSM表空间下才能用的,它非常聪明,能在允许DML操作的同时,逐步地将有数据的块向段的前端移动,然后回收末端空闲的块,从而降低高水位线,这个过程可以分两步走:先ALTER TABLE ... ENABLE ROW MOVEMENT开启行移动,然后ALTER TABLE ... SHRINK SPACE执行收缩,还有一个传统方法是ALTER TABLE ... MOVE,它相当于给表“搬了个家”,会重新组织表的数据块,并重置高水位线,但在这个过程中,表通常是不可用的,而且需要重建索引,根据Oracle的官方建议和社区经验,对于大表的空间回收,SHRINK通常是线上操作的首选,因为它对业务影响最小;而TRUNCATE适用于可以接受瞬间锁定的清空操作。
再提几个实用的经验点。
一是关于索引的碎片整理,索引也是段,也会因为频繁的增删改而产生碎片,判断索引是否需要重建,不要凭感觉,可以查询DBA_INDEXES视图中的PCT_USED等统计信息,或者使用ANALYZE INDEX ... VALIDATE STRUCTURE命令来分析,如果碎片化确实严重,使用ALTER INDEX ... REBUILD在线重建索引是个好办法。
二是注意延迟段创建这个特性,从Oracle 11gR2开始,有个默认开启的特性叫“延迟段创建”,意思是,你创建一张表的时候,Oracle并不会立即为它分配段和初始区,而是要等到你插入第一条数据时才分配,这本来是个优化,但对于一些期望表创建后就能看到相关元数据的脚本或应用,可能会造成困惑,如果不需要,可以在建表时指定SEGMENT CREATION IMMEDIATE。
段管理看似底层,但直接影响着数据库的性能和空间效率,理解了ASSM的工作原理,掌握了处理高水位线的几种方法,就能解决大部分常见的存储性能问题,这些内容在Oracle的官方管理手册和很多资深DBA的博客分享中都有深入探讨,多实践几次就能摸清门道了。
本文由瞿欣合于2026-01-17发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://waw.haoid.cn/wenda/82365.html
