应优先检查v$active_session_history中db file scattered read或enq: cf - contention的高占比,结合dba_lobs确认basicfile+nologging是否导致性能问题:前者引发lob段全扫,后者加剧控制文件锁争用,需通过move lob切换存储并验证真实空间占用。
直接看 v$active_session_history 里有没有高比例的 db file scattered read 或 enq: cf - contention,再结合 dba_lobs 确认是不是 basicfile + nologging 在联手拖垮性能。
查 ASH 是否在反复刷 db file scattered read 并指向 LOB 段
这不是磁盘慢,是 SQL 在全扫 LOB 表空间。LOB 字段若仍用 BasicFile,且没走索引或谓词下推,执行计划常退化为物理读大段数据块。
- 执行:
SELECT sql_id, event, count(*) FROM v$active_session_history WHERE event = 'db file scattered read' AND sample_time > SYSDATE - 1/24 GROUP BY sql_id, event ORDER BY 3 DESC; - 对高频
sql_id查执行计划:SELECT * FROM dba_hist_sql_plan WHERE sql_id = '&sql_id' AND object_name LIKE 'SYS_LOB%';—— 如果OBJECT_NAME是SYS_LOB%,基本坐实是 LOB 段扫描 - 注意
P1(file#)和P2(block#):若集中在几个文件,说明这些文件里堆着未迁移的BasicFile段,不是整体 IO 问题
确认 LOB 存储类型和日志模式是否双踩雷
BasicFile + NOLOGGING 是典型组合陷阱:前者导致空间膨胀、查询慢;后者引发 enq: CF - contention,尤其在批量写入时。
- 查当前设置:
SELECT table_name, column_name, securefile, logging, in_row, chunk FROM dba_lobs WHERE owner = 'YOUR_SCHEMA' AND table_name = 'YOUR_TABLE'; -
securefile = 'NO'且logging = 'NO'就是双重风险点 - 别只信表定义——
MOVE前改LOGGING不生效,存量数据仍走旧路径;必须先ALTER TABLE ... MOVE LOB才能真正切换存储引擎
区分 enq: CF - contention 是真由 LOB 引起,还是误判
这个等待事件表面是控制文件锁争用,根源往往是 LOB 的 NOLOGGING 模式迫使每个 DML 都要同步更新控制文件 SCN。
- 查实时会话:
SELECT sid, event, blocking_session, sql_id FROM v$session WHERE event = 'enq: CF - contention'; - 如果
sql_id对应的语句含INSERT/UPDATELOB 字段,且表的DBA_LOBS.LOGGING = 'NO',基本可锁定 - 临时表可豁免,但业务表不能:哪怕只是导出或归档场景,只要并发写 LOB,
NOLOGGING就可能卡住整个实例的 CF 锁队列 - 验证方法:临时
ALTER TABLE ... MODIFY LOB (...) (LOGGING);后观察等待是否下降——但注意这不解决空间和查询慢,只缓解锁争用
别跳过真实空间占用验证,DBA_SEGMENTS.BYTES 在 SecureFiles 下会严重失真
迁移成 SecureFile 后,COMPRESS 和 DEDUPLICATE 会让分配空间(BYTES)和实际使用(USED_BYTES)差几倍,仅靠 DBA_SEGMENTS 会误判“没缩容”。
- 查真实用量:
DECLARE used_bytes NUMBER; lob_bytes NUMBER; BEGIN DBMS_SPACE.SPACE_USAGE('YOUR_SCHEMA', 'YOUR_TABLE', 'LOB', 0, used_bytes, lob_bytes, NULL); DBMS_OUTPUT.PUT_LINE('Used: ' || used_bytes); END; - 旧
BasicFile段不会自动删,得手动清理:SELECT segment_name, bytes FROM dba_segments WHERE segment_name LIKE 'SYS_LOB%&old_object_id';确认无依赖后再DROP SEGMENT - 迁移窗口内,
UNDO_RETENTION必须调高,否则MOVE过程中易报ORA-01555—— 尤其当原表有长事务在读取 LOB 列时











