Oracle 19c无READ ANY TABLE权限,仅支持SELECT ANY TABLE但ADG备库失效;安全只读方案须在备库显式授予对象级SELECT权限,并通过角色统一管理,同义词、视图需单独授权。
read any table 在 oracle 19c 中根本不存在——这是个常见误解,实际语法会直接报错 ora-01931: cannot grant read any table。oracle 只支持 select any table,而它在 adg 物理备库上又完全失效。真正能落地的只读方案,必须绕开系统级权限,走对象级显式授权。
ADG 备库上 SELECT ANY TABLE 为什么一定失败
物理备库(READ ONLY WITH APPLY)禁止任何隐式字典写操作,而 SELECT ANY TABLE 的权限校验过程会尝试访问数据字典表(如 obj$、tab$),触发只读保护机制。即使你用 SYS 执行了 GRANT SELECT ANY TABLE TO ro_user,后续执行 SELECT * FROM CMSPROD.PORTAL_USER_PROFILE 仍会抛出 ORA-01031: insufficient privileges。
- 这不是权限没刷或缓存延迟,是 Oracle 内核硬限制
-
SELECT ANY DICTIONARY同样无效,备库不开放“任意读字典”通道 - 哪怕主库已同步该 schema,备库上也必须显式执行
GRANT SELECT ON CMSPROD.TABLE_NAME TO user
如何在备库上安全创建只读用户
核心动作必须在备库实例上完成,且所有授权语句都需明确指定 schema 和表名:
- 先确认目标对象存在:
SELECT owner, table_name FROM dba_tables WHERE owner = 'CMSPROD' AND table_name = 'PORTAL_USER_PROFILE' - 创建用户并赋予基础连接能力:
CREATE USER cmsreadonly IDENTIFIED BY "xxx" DEFAULT TABLESPACE users;GRANT CREATE SESSION TO cmsreadonly - 逐表授权(不可省略 schema):
GRANT SELECT ON CMSPROD.PORTAL_USER_PROFILE TO cmsreadonly - 若需批量,用查询生成脚本(在备库执行):
SELECT 'GRANT SELECT ON CMSPROD.' || table_name || ' TO cmsreadonly;' FROM dba_tables WHERE owner = 'CMSPROD'
用角色封装比直接授用户更可控
直接对用户授一堆 GRANT SELECT ON ... 很难维护,稍有遗漏就查不到表。推荐建角色统一管理:
- 创建角色:
CREATE ROLE app_readonly - 把表权限授给角色(不是用户):
GRANT SELECT ON CMSPROD.PORTAL_USER_PROFILE TO app_readonly - 再把角色给用户:
GRANT app_readonly TO cmsreadonly - 多租户环境(CDB/PDB)下,角色必须在目标 PDB 内创建并授权,跨 PDB 不继承
注意:角色本身不带登录能力,CREATE SESSION 仍需单独授予用户。
同义词和视图访问要单独处理
只读角色默认不覆盖同义词、视图、物化视图的访问权:
- 同义词只是别名,不继承底层权限,必须对原表/视图单独授权
- 自定义视图需对视图本身授
SELECT,不是对基表授了就行 - 动态性能视图(如
v$session)需额外授SELECT_CATALOG_ROLE,但该角色含大量隐式权限,生产环境慎用;更稳妥的是建包装视图再授权 - 数据字典表(如
dba_tables)无法通过普通只读角色访问,SELECT ANY DICTIONARY在备库同样被禁用
最容易被忽略的是:备库上用户能否看到某个表,不仅取决于权限,更取决于该 schema 是否已完成传输、是否在 db_recovery_file_dest 中完成应用。权限再对,表没同步过来,照样 ORA-00942。


















