最直接路径是查DBA_USERS与DBA_AUDIT_TRAIL(或UNIFIED_AUDIT_TRAIL)组合判断:先排除内置账号,再筛选近180天无LOGON记录且状态为OPEN的用户,但需确保已启用成功会话审计,且必须人工验证JOB、DB Link等隐式使用场景。

查 DBA_USERS + DBA_AUDIT_TRAIL 是最直接路径
Oracle 不自带“账号是否被用过”的布尔字段,得靠组合判断:先筛出非 Oracle 内置账号(避免误删 SYSTEM、SYS 等),再排除近期有登录/操作记录的账号。核心是依赖审计日志——没开审计就无法可靠识别“从未使用”,这点必须前置确认。
常见错误是只查 DBA_USERS 里的 CREATED 时间,以为“创建半年没改密码=没用过”,但实际可能被应用静默调用;也有人查 V$SESSION,但它只反映当前连接,历史行为完全看不到。
- 必须已启用标准审计:
AUDIT SESSION;或更细粒度如AUDIT SELECT TABLE BY hr;,否则DBA_AUDIT_TRAIL为空 - 默认审计只记录失败登录(
FAILED_LOGIN_ATTEMPTS),要捕获成功会话需显式开启:AUDIT CREATE SESSION WHENEVER SUCCESSFUL; - 若用统一审计(Oracle 12c+),查
UNIFIED_AUDIT_TRAIL替代DBA_AUDIT_TRAIL,字段名略有差异(如ACTION_NAME替代ACTION)
过滤内置账号和系统保留用户
直接 SELECT username FROM dba_users 会拉出 40+ 个 Oracle 自带账号(如 XS$NULL、DIP、GSMADMIN_INTERNAL),这些不能动,也不该纳入“冗余”评估范围。硬编码排除比模糊匹配更安全。
执行前务必确认当前数据库版本——19c 后新增了 ORDDATA、MDSYS 等组件用户,12c 则有 APPQOSSYS,漏掉会导致误删。
- 通用排除列表(适用于 12c–19c):
WHERE username NOT IN ('SYS','SYSTEM','SYSBACKUP','SYSDG','SYSKM','ROOT','C##SECURE','XS$NULL','DIP','GSMADMIN_INTERNAL','GSMUSER','GSMROOTUSER','DBSNMP','OUTLN','AUDSYS','OLAPSYS') - 避免用
username LIKE 'C##%'粗暴过滤容器用户,因为部分多租户环境业务账号也按此命名规范 - 检查账号是否被 profile 限制:
SELECT username, profile FROM dba_users WHERE account_status = 'OPEN',若 profile 为DEFAULT且密码策略宽松,更需谨慎
用审计日志反向标记“活跃账号”
思路是:先取出所有待评估账号,再从 DBA_AUDIT_TRAIL 中找出近 6 个月有 ACTION_NAME = 'LOGON' 的用户名,两者取差集。别用 MAX(NTIMESTAMP#) 聚合后比较,容易因索引缺失导致全表扫描卡死。
性能关键点在于 DBA_AUDIT_TRAIL 通常巨大,不加时间过滤直接 JOIN 可能跑数小时。生产库建议先建函数索引:CREATE INDEX idx_audit_user_time ON dba_audit_trail(username, ntimestamp#) COMPRESS 2;
- 基础查询(适配 12c+ 统一审计):
SELECT u.username FROM dba_users u WHERE u.username NOT IN ('SYS','SYSTEM',...) AND u.account_status = 'OPEN' AND u.username NOT IN ( SELECT DISTINCT username FROM unified_audit_trail WHERE action_name = 'LOGON' AND event_timestamp > SYSDATE - 180 ); - 若审计日志未归档,
unified_audit_trail默认只存最近 90 天,需确认AUDIT_UNIFIED_ENABLED参数及清理策略 - 注意
username在审计视图中可能为 NULL(如外部认证登录),这类记录不影响判断,可忽略
最后一步:人工交叉验证不可跳过
即使审计显示某账号“零登录”,仍可能通过以下方式被使用:应用直连字符串硬编码、中间件连接池复用、JOB 调用(查 DBA_SCHEDULER_JOBS)、甚至 DB Link 被其他库调用(查 DBA_DB_LINKS)。自动脚本只能筛出高概率冗余账号,不能替代人工确认。
最容易被忽略的是密码过期状态——ACCOUNT_STATUS 为 'EXPIRED & LOCKED' 的账号,如果其 profile 设置了 PASSWORD_LIFE_TIME UNLIMITED,说明它被刻意停用而非自然废弃,这类应单独归档而非删除。
- 必查关联对象:
SELECT object_name, object_type FROM dba_objects WHERE owner = 'XXX' AND created ,若存在一年前创建且无后续 DML 的表/过程,佐证闲置 - 检查是否有 JOB:
SELECT job_name, state FROM dba_scheduler_jobs WHERE owner = 'XXX';,哪怕状态是DISABLED也要看 last_start_date - 导出账号权限快照:
SELECT * FROM dba_role_privs WHERE grantee = 'XXX';,若含DBA或EXP_FULL_DATABASE,删除前必须走变更流程


















