select any table 不是 schema 级权限,而是全库级高危权限,无法实现可控只读;它不区分 schema、不可按 schema 回收,且在 adg 备库上因字典表只读而强制失效,必须改用角色+显式对象授权方案。
不能用 select any table 实现 schema 级别的只读权限——它根本不是 schema 级的,而是全库级的高危权限,且在 adg 备库上直接失效。
为什么 SELECT ANY TABLE 不是 Schema 级权限
它不区分 schema、不绑定对象、不随 schema 变化而自动适配。授予后,用户能查 SYS.AUD$、SYSTEM.LOGSTDBY$、HR.EMPLOYEES,也能查未来新建的任意普通表,完全失控。Oracle 没有“Schema 级 ANY 权限”这个概念,SELECT ANY TABLE 的作用域是整个 CDB(或非 CDB 数据库),和 schema 无关。
常见错误现象:
- 执行
GRANT SELECT ANY TABLE TO app_ro;后,SELECT * FROM app_schema.orders;能跑通,但SELECT * FROM dba_users;也能跑通——这不是预期行为,是越权暴露 - 后续想回收“只对 app_schema 的权限”,发现无法按 schema 撤销,只能整权收回或手动逐表
REVOKE,维护成本爆炸
SELECT ANY TABLE 在 ADG 备库上必然报 ORA-01031
ADG 物理备库处于 READ ONLY WITH APPLY 或 READ ONLY 状态,所有数据字典表均为只读。而 SELECT ANY TABLE 内部依赖对 OBJ$、USER$ 等字典表的隐式访问(含部分写逻辑),Oracle 主动禁用该权限以保一致性。即使你用 SYS 登录并成功执行了授权语句,后续任何 SELECT 都会触发 ORA-01031: insufficient privileges。
关键点:
- 这不是缓存没刷、不是权限没生效,是 Oracle 的硬性限制
-
SELECT ANY DICTIONARY同样无效,备库不开放“任意读字典”的通道 - 唯一可行路径是显式授权具体对象:
GRANT SELECT ON CMSPROD.PORTAL_USER_PROFILE TO cmsreadonly;
真正实现 Schema 级只读的正确做法
必须放弃“ANY”思维,转向对象级显式控制。核心是:限定 schema + 分类型授权 + 角色封装。
- 先确认目标 schema 已同步到备库:
SELECT COUNT(*) FROM dba_tables WHERE owner = 'CMSPROD';,若为 0,说明主库未传输该 schema 元数据 - 生成表级授权语句(在备库上执行):
SELECT 'GRANT SELECT ON CMSPROD.' || table_name || ' TO cmsreadonly;' FROM dba_tables WHERE owner = 'CMSPROD' AND temporary = 'N'; - 物化视图需单独处理:
SELECT 'GRANT SELECT ON CMSPROD.' || mview_name || ' TO cmsreadonly;' FROM dba_mviews WHERE owner = 'CMSPROD'; - 视图必须单独授权,不能假设“授了表就等于能查视图”——视图定义中引用的底层对象也必须已授权
- 创建角色集中管理:
CREATE ROLE cmprod_reader; GRANT SELECT ON CMSPROD.T1 TO cmprod_reader;……再GRANT cmprod_reader TO cmsreadonly;
容易被忽略的三个落地细节
权限写完不等于可用。以下三点常被跳过,导致上线后应用报 ORA-00942 或静默失败:
-
CREATE SESSION必须显式授予,否则连不上库:GRANT CREATE SESSION TO cmsreadonly; - 同义词本身不继承权限,如果应用代码写的是
SELECT * FROM portal_user_profile;(无 schema 前缀),必须额外建私有同义词:CREATE SYNONYM portal_user_profile FOR CMSPROD.PORTAL_USER_PROFILE; - 大小写陷阱:若表名建时加了双引号(如
"portalUserProfile"),授权时必须严格匹配:GRANT SELECT ON CMSPROD."portalUserProfile" TO cmsreadonly;,否则仍报ORA-00942
Schema 级只读的本质,不是“禁止写”,而是“只开指定的读门”。SELECT ANY TABLE 是一扇敞开的、没锁的、通向所有房间的门——你永远不知道谁在哪个房间里改了什么,或者正在看什么。











