oracle 12c 不支持“不可见分区”,仅支持不可见列(invisible columns);隐藏分区数据需通过read only分区+分区剪枝、行级安全策略(dbms_rls)、视图封装等上层机制实现。
oracle 12c 没有“不可见分区”(invisible partition)这个特性。你看到的“不可见”只适用于列(invisible columns),不是分区。
常见误解是把 INVISIBLE 列、INVISIBLE 索引、以及分区的 INACTIVE 或 READ ONLY 状态混为一谈——但 Oracle 官方文档和所有已知版本(包括 12.1/12.2/19c/21c)中,分区本身无法被标记为 INVISIBLE。
那为什么有人会搜“隐藏特定分区数据”? 通常真实需求是这几种之一:
- 想让某分区的数据对普通查询“不可见”,比如归档历史分区但又不 drop
- 想控制应用访问范围,避免误查旧分区
- 想做灰度切换,临时屏蔽某个分区的读写
这些目标,得靠别的机制实现,而不是幻想分区能“隐形”。
用 READ ONLY + 分区剪枝限制可见性
这是最接近“隐藏分区数据”效果的合法做法:把目标分区设为只读,并配合查询条件强制走分区剪枝(partition pruning)。
-
ALTER TABLE t MODIFY PARTITION p_old READ ONLY; - 查询时必须显式带上分区键条件(如
WHERE sale_date >= DATE '2025-01-01'),否则优化器可能跳过剪枝,导致全分区扫描(包括只读分区) - 应用层需确保 SQL 不写成
SELECT * FROM t这类无过滤语句,否则只读分区仍会参与执行计划 - 注意:
READ ONLY分区仍会在SELECT中返回数据,只是不能INSERT/UPDATE/DELETE;它不是“隐藏”,而是“冻结可见”
用虚拟列 + INVISIBLE 列模拟逻辑隔离
如果你真想让某批数据“在 SELECT * 下不出现”,可行路径是:把原分区键字段转为 INVISIBLE,再加一个显式可控的虚拟列做路由标识。
- 创建表时定义分区键列为
INVISIBLE:CREATE TABLE sales (id NUMBER, amt NUMBER, sale_dt DATE INVISIBLE) PARTITION BY RANGE (sale_dt) (...); - 插入数据必须显式指定
sale_dt:INSERT INTO sales (id, amt, sale_dt) VALUES (1, 100, DATE '2024-01-01'); - 查询时若不写
sale_dt,该列不会出现在结果里,但分区裁剪仍依赖它 —— 所以你得额外加一个可见的虚拟列(如is_active AS (CASE WHEN sale_dt >= DATE '2025-01-01' THEN 1 ELSE 0 END) VIRTUAL),供业务判断是否“可见” - 缺点:
INVISIBLE列不能用于分区键(Oracle 报错ORA-54019),所以你只能把它作为辅助字段,主分区键还得用另一个可见列
真正能“隐藏分区数据”的替代方案
如果目标是让某分区彻底不出现在常规查询结果中,只有特定权限或上下文才能访问,考虑:
-
DBMS_REDACT:对整个分区的数据做动态脱敏(如把salary在旧分区里全变成 0),但它作用于列值,不区分分区 - 行级安全策略(
DBMS_RLS):在策略函数里判断sale_dt是否属于目标分区范围,然后动态加AND 1=0过滤掉整块数据 - 物理隔离:把旧分区
EXCHANGE到一个独立表,再GRANT/REVOKE权限控制访问 - 视图封装:建视图只
UNION ALL当前活跃分区,不包含旧分区 —— 这是最常用、最可控的方式
别指望分区自己“隐形”。Oracle 的分区本质是物理组织方式,不是访问控制层。真正要隐藏数据,得靠权限、策略、视图或脱敏这些上层手段。最容易踩的坑,就是以为加个 INVISIBLE 就能让分区消失 —— 它只会让你的 DDL 报错,或者让分区剪枝失效。











