oracle 12c自增列的高水位(hwm)属于表段而非序列,存储过程无法管理“序列hwm”(因序列无hwm概念);可执行alter table ... shrink space或truncate降低表hwm,但需注意enable row movement及事务影响。
oracle 12c 的自增列(generated as identity)底层仍依赖隐式序列,但这个序列不可见、不可直接操作,因此你无法在存储过程中「管理」它的高水位——高水位(hwm)属于表段(segment),不是序列的属性。真正需要关注的是:表的 hwm 过高导致全表扫描变慢,而自增列本身不会引发 hwm 异常,反而是大量 insert + delete 后残留的 hwm 才是性能瓶颈。
为什么不能在存储过程中“管理序列的高水位”
序列(SEQUENCE)没有高水位概念。它只维护当前值(CURRVAL)和下一个值(NEXTVAL),不占用数据块,也不影响表的物理存储结构。所谓“序列高水位”是常见误解。真正有 HWM 的是表本身——由 USER_TABLES.BLOCKS 反映,它取决于该表历史上分配过的最大 extent 数量。
-
GENERATED ALWAYS AS IDENTITY创建的列,其背后序列名形如ISEQ$$_<number></number>,用户无法SELECT、ALTER或DROP它 - 即使你手动建一个显式序列并在触发器中使用,序列值耗尽或跳号也不会抬高表的 HWM
- HWM 只随表段扩展(如大批量插入、
MOVE、SHRINK)变化,与序列无关
存储过程里能做的实际动作:重置表 HWM
如果你的业务场景是定期清理历史数据(比如日志表),又希望后续查询变快,可在存储过程中调用 DDL 操作收缩表空间。注意:这需要 ALTER TABLE ... SHRINK SPACE 权限,且表必须启用行移动(ENABLE ROW MOVEMENT)。
- 先确保表支持收缩:
ALTER TABLE your_table ENABLE ROW MOVEMENT; - 在存储过程中执行:
EXECUTE IMMEDIATE 'ALTER TABLE your_table SHRINK SPACE COMPACT'; - 如果想彻底释放空间并重置 HWM 到最低(类似
TRUNCATE效果但保留数据),用:EXECUTE IMMEDIATE 'ALTER TABLE your_table SHRINK SPACE'; - 注意:
SHRINK会加SSX锁,阻塞 DML;生产环境建议在低峰期执行
替代方案:用 TRUNCATE + INSERT 替代 DELETE
若业务允许清空整张表(例如中间临时表),TRUNCATE 是最直接降低 HWM 的方式——它会重置 BLOCKS 为接近 0,并释放空间。但 TRUNCATE 是 DDL,不能回滚,也不能在自治事务外直接用于存储过程中被调用(会隐式提交)。
- 可行写法:
EXECUTE IMMEDIATE 'TRUNCATE TABLE your_table'; - 风险点:执行后当前事务已提交,后续语句无法回滚;若需事务一致性,改用
DELETE+SHRINK组合 - 自增列在
TRUNCATE后,其隐式序列的CURRVAL不会重置(12c+ 默认行为),下次INSERT仍从原值继续——这点常被忽略
真正要警惕的坑:自增列 + 高并发 INSERT 导致的序列争用
虽然不涉及 HWM,但这是 12c 自增列在存储过程中高频使用的实际痛点。当多个会话同时插入同一张自增表时,底层隐式序列的 NEXTVAL 获取可能成为瓶颈,尤其在未启用 CACHE 时。
- 验证是否争用:查
v$enqueue_statistics中US(user lock)或SV(sequence cache)等待 - 解决方法:对自增列所在表,手工创建显式序列(带大
CACHE值),再用触发器或应用层控制赋值——绕过隐式序列限制 - 例如:
CREATE SEQUENCE seq_t1_id START WITH 1 INCREMENT BY 1 CACHE 10000 NOORDER;,然后在存储过程中用seq_t1_id.NEXTVAL
归根结底,HWM 是表的物理特性,不是序列的;存储过程能干预的只有表结构操作(SHRINK、TRUNCATE)或绕过隐式序列改用手动序列。最容易被忽略的是:SHRINK 需要提前 ENABLE ROW MOVEMENT,而 TRUNCATE 会破坏事务边界——这两点在封装进存储过程前必须明确约束条件。











