应实时查ASH中INSERT会话的等待事件,而非等导入结束;插入慢主因是redo写不过来、DBWR跟不上或索引重建拖累,并非SQL执行慢。

直接查ASH里INSERT会话的等待事件
别等导入结束再翻日志,impdp或SQL*Loader跑着的时候就该看ASH。插入慢往往不是SQL本身执行慢,而是被后台资源卡住——redo写不过来、DBWR跟不上、索引重建拖住并行度。用v$active_session_history抓最近5分钟样本最准,因为ASH内存只保留约1小时,且高负载下可能更短。
执行这个查询定位真正在等什么:
SELECT event, wait_class, COUNT(*) cnt FROM v$active_session_history WHERE sql_opname = 'INSERT' AND sample_time > SYSDATE - INTERVAL '5' MINUTE GROUP BY event, wait_class ORDER BY cnt DESC;
- 如果
log file switch (checkpoint incomplete)排第一,说明redo log太小,尤其在NOARCHIVELOG模式下;11g默认50MB根本扛不住批量插入 - 如果
free buffer waits高频出现,不是磁盘慢,是DBWR线程数太少或buffer cache过小,导致前台反复等空闲块 - 如果
enq: TX - row lock contention集中,检查是不是没提交的大事务在前面堵着,或者唯一键冲突(p1raw末两位是04)
区分“INSERT执行慢”和“INSERT被拖慢”
ASH里看到某条INSERT语句大量样本,不代表它单次执行花了几十秒。要结合session_state和event判断:
-
session_state = 'ON CPU'且event为空 → 真在跑,可能是逻辑复杂、索引分裂多、或绑定变量引发数据倾斜 -
session_state = 'WAITING'且event = 'library cache lock'→ 可能刚执行完DDL(比如CREATE OR REPLACE PACKAGE),锁还没释放,后续INSERT全被拦住 -
session_state = 'WAITING'且event = 'db file sequential read'→ 不是INSERT慢,是它触发的递归SQL(比如索引维护)在读数据字典或undo段
验证方法:查v$sql里对应sql_id的elapsed_time / executions平均值。如果只有几毫秒,但ASH里一堆30s+样本,基本可排除SQL本身问题。
RAC环境下必须用gv$active_session_history
单节点查v$active_session_history只能看到本实例的采样。如果INSERT慢发生在node2,你在node1上执行查询,结果就是空。RAC必须用gv$active_session_history,否则永远找不到根因。
另外,impdp启动多个worker时,每个worker对应一个sid,但program字段通常是DW00、DW01这类,不是oracle@host。查阻塞链时,得用blocking_session和final_blocking_session一起追,不能只看当前会话的blocking_session。
-
final_blocking_session = 0或NULL→ 那个会话就是根阻塞源,大概率是忘了COMMIT的批处理 -
p1raw = '54580006'→ mode=6,标准行锁;p1raw = '54580004'→ mode=4,很可能是唯一键冲突,杀会话没用
别漏掉统计信息和索引重建的隐性开销
11g中,impdp默认会在导入完成后自动重建索引并收集统计信息。这两个操作不走并行,且ANALYZE TABLE COMPUTE STATISTICS在大表上可能卡死几十小时——你看到的“插入完成但任务没结束”,其实是它在后台默默干这事。
- 导出时加
EXCLUDE=STATISTICS,INDEX,导入后再手工控制收集时机 - 导入命令里显式加
STATISTICS=NONE和INDEXES=NONE,避免默认行为拖垮整体节奏 - 如果必须重建索引,确保表上没函数索引(如
UPPER(name))或位图索引,它们重建更耗时
真正卡住批量INSERT的,往往不是INSERT那条语句本身,而是它背后那一连串Oracle自动触发的维护动作——redo、DBWR、锁、统计信息,每一环都可能成为瓶颈。ASH只给你快照,但快照里的event和session_state组合,才是打开黑盒的钥匙。


















