不能仅凭dba_users.last_login判断僵尸用户,应结合v$session活跃状态、TEMP段占用及对象依赖综合验证。

不能只看 dba_users.last_login 字段来判断僵尸用户——它在连接池、中间件或直连场景下基本不更新,误判率极高。
查会话活跃度比查登录时间更可靠
Oracle 不强制记录用户登录时间,尤其应用通过连接池复用连接时,last_login 常为空或停留在建库初期。真正能反映“是否还在用”的是当前会话行为:
-
v$session中status = 'ACTIVE'且last_call_et :正在干活,肯定不是僵尸 -
status = 'INACTIVE'但last_call_et > 86400(24 小时):需进一步确认是否占资源 -
sql_id IS NULL且event LIKE '%idle%':大概率已断连但进程未释放
执行这句就能筛出高嫌疑对象:
SELECT sid, serial#, username, status, last_call_et, sql_id, event FROM v$session WHERE username = 'YOUR_USER' AND status = 'INACTIVE' AND last_call_et > 86400 AND sql_id IS NULL;
必须验证是否还在占 TEMP 段
即使会话状态是 INACTIVE,只要它还在用临时表空间,就不能直接锁账号——否则 v$sort_usage 里 blocks 不降,TEMP 表空间迟早爆满。
先关联查:
SELECT s.sid, s.serial#, u.tablespace, u.blocks * 8 / 1024 AS mb_used FROM v$sort_usage u JOIN v$session s ON u.session_addr = s.saddr WHERE s.username = 'YOUR_USER' AND u.tablespace = 'TEMP';
如果返回结果非空,说明该用户有会话正挂着 TEMP 段,此时:
- 不能跳过清理直接
ALTER USER ... ACCOUNT LOCK - 必须先
ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE - 若执行后状态变成
KILLED但blocks不降,得查v$process.spid并kill -9对应 OS 进程(仅 Linux/Unix)
锁定前检查隐式依赖,别让视图/DBLINK崩了
一个用户被长期不用,不代表它的对象没人引用。贸然锁号可能让其他 schema 的视图报错 ORA-00942,或让 DBLINK 查询失败。
重点查三类依赖:
- 被其他用户视图/同义词引用的表:
SELECT owner, name, type FROM dba_dependencies WHERE referenced_owner = 'YOUR_USER' - 作为 DEFINER 执行的存储过程:
SELECT owner, name, authid FROM dba_procedures WHERE definer = 'YOUR_USER' - 是否存在 DBLINK 指向该用户:
SELECT owner, db_link FROM dba_db_links WHERE username = 'YOUR_USER'
发现依赖后,不要自行决定删或锁,先找对应业务方确认是否可停用。
锁定账号比删除安全,但得配 IMMEDIATE 清残留
生产环境首选 ALTER USER ... ACCOUNT LOCK,它不删对象、不破依赖、审计可追溯。但注意两点:
- 锁定操作不影响已存在的会话,所以必须在锁之前完成
KILL SESSION,否则残留会话继续占资源 - 如果目标用户属于某个启用了
FAILED_LOGIN_ATTEMPTS的 profile,加个FAILED_LOGIN_ATTEMPTS 3能让后续审计看到操作意图 - 执行锁定后,立刻再查一次
v$session和v$sort_usage,确保无残留——这是最容易被跳过的一步
真正麻烦的从来不是“怎么锁”,而是“锁完发现 TEMP 段还占着、视图突然报错、DBLINK 断连”。每一步清理动作都得有验证闭环,而不是靠命令执行成功就以为完事了。











