直接查DBA_SYS_PRIVS会漏掉通过RESOURCE或DBA角色隐式授予的UNLIMITED TABLESPACE权限,须联合DBA_SYS_PRIVS和DBA_ROLE_PRIVS查询,并处理ADMIN_OPTION='YES'情况;REVOKE前必须验证权限存在,否则报ORA-01952;回收后需立即补配额,否则建表报ORA-01536;收缩数据文件前须确认HWM可降。

查哪些用户真有 UNLIMITED TABLESPACE 权限
直接查 DBA_SYS_PRIVS 会漏掉隐式授予的情况——比如用户被赋予了 RESOURCE 或 DBA 角色,而这两个角色自带 UNLIMITED TABLESPACE。光看显式授权等于白查。
真正有效的判断方式是组合查询:
SELECT DISTINCT grantee FROM dba_sys_privs WHERE privilege = 'UNLIMITED TABLESPACE' AND admin_option = 'NO' UNION SELECT grantee FROM dba_role_privs r JOIN dba_sys_privs p ON r.granted_role = p.grantee WHERE p.privilege = 'UNLIMITED TABLESPACE' AND p.admin_option = 'NO';
注意:admin_option = 'YES' 的用户也能转授该权限,必须一并处理,否则回收后可能被二次扩散。
执行 REVOKE 前必须确认权限真实存在
REVOKE UNLIMITED TABLESPACE FROM username 不是“有就收、没有就跳过”——它会严格校验该用户是否被显式授予过该权限。如果没授过,立刻报 ORA-01952: system privilege not granted,命令中断。
所以不能写脚本批量跑 REVOKE,必须先用上一步的查询结果做输入源。例如:
BEGIN
FOR u IN (SELECT grantee FROM your_unlimited_list) LOOP
EXECUTE IMMEDIATE 'REVOKE UNLIMITED TABLESPACE FROM ' || u.grantee;
END LOOP;
END;但这个块仍可能中途失败(比如某用户权限来自角色而非直授),建议逐条手工执行并捕获错误,避免误伤。
回收后用户建表立即报 ORA-01536?补配额才是关键
回收 UNLIMITED TABLESPACE 后,用户在所有表空间的配额都变成 0,包括其 DEFAULT TABLESPACE。此时哪怕只建一个空表,也会报 ORA-01536: space quota exceeded for tablespace 'USERS'。
必须立刻补配额,常见做法有:
-
ALTER USER username QUOTA 10M ON users;(设有限值,最安全) -
ALTER USER username QUOTA UNLIMITED ON users;(仅放开指定表空间,不恢复全局无限) - 避免
GRANT RESOURCE TO username——它会再次带出UNLIMITED TABLESPACE,白忙一场
别忘了 TEMP 表空间:虽然不存数据,但排序、临时段失败会导致 SQL 中断,需单独确认 TEMP 配额是否足够(CREATE GLOBAL TEMPORARY TABLE 也受限制)。
收缩数据文件前先确认 HWM 是否可降
用户配额回收只是第一步。如果他们之前建过大量对象又删了,表空间里空闲空间多,但数据文件物理大小没变——因为高水位线(HWM)卡在高位不动。
先查可回收空间:
SELECT a.file#, a.name,
(a.bytes - b.hwm * a.block_size) / 1024 / 1024 AS reclaimable_mb,
'ALTER DATABASE DATAFILE ''' || a.name || ''' RESIZE ' ||
CEIL(b.hwm * a.block_size / 1024 / 1024) || 'M;' AS cmd
FROM v$datafile a,
(SELECT file_id, MAX(block_id + blocks - 1) hwm
FROM dba_extents
GROUP BY file_id) b
WHERE a.file# = b.file_id(+)
AND (a.bytes - b.hwm * a.block_size) > 0;执行 RESIZE 前,确保目标大小 ≥ HWM 对应位置,否则报错;且该数据文件不能是自动扩展(AUTOEXTENSIBLE = 'YES')的主文件,否则需先 ALTER DATABASE DATAFILE ... AUTOEXTEND OFF。


















