oracle不支持limit语法,需用rownum伪列限制删除行数,如delete from table where ... and rownum

为什么不能直接用 DELETE FROM table WHERE ... LIMIT 10000
Oracle 没有 LIMIT 语法,DELETE ... WHERE ... AND ROWNUM 是唯一原生分页删除手段,但必须注意:<code>ROWNUM 在 WHERE 执行前就已生成,写成 WHERE ROWNUM 会先取前 10000 行再过滤,结果可能远少于预期。正确写法是嵌套子查询或用 <code>ROWID 切片。
用 ROWNUM 分批删时怎么避免漏删或重复删
核心陷阱是条件字段存在索引缺失、NULL 值或数据倾斜,导致每次 ROWNUM 截断位置不稳定。推荐组合使用:
- 始终带上唯一有序字段(如主键
id或时间戳create_time)作为游标锚点 - 写成
WHERE id > :last_id AND status = 'INACTIVE' AND ROWNUM ,每次记录最后处理的 <code>id - 避免只依赖
ROWNUM+ 非唯一条件(如WHERE dept = 'SALES'),否则可能跳过某些行 - 若无法加游标字段,改用
ROWID分块(需先执行rowid_chunk.sql生成范围),更可靠但需额外步骤
事务提交频率和锁表风险怎么平衡
每删 1000–5000 行提交一次是常见折中点,但具体要看表大小和业务容忍度:
- 太小(如 100 行/次):事务开销大,
UNDO和重做日志频繁刷写,反而慢 - 太大(如 50000 行/次):可能触发
ORA-01555快照过旧,或长时间持有 DML 锁影响并发 - 关键动作必须加
COMMIT,不能只靠循环末尾一次提交——否则失败时全部回滚,重试成本高 - 对超大表(亿级),建议配合
ALTER SESSION ENABLE PARALLEL DML和并行 hint,但仅对非分区表有效且需 DBA 授权
脚本里要不要加异常捕获和日志输出
必须加,否则一个用户权限不足或约束冲突就会中断整个流程:
- 用
EXCEPTION WHEN OTHERS THEN捕获,但别吞掉SQLCODE—— 至少记录SQLERRM和当前批次条件 -
DBMS_OUTPUT.PUT_LINE仅用于调试,生产环境建议写入日志表(如LOG_DELETE_HISTORY) - 特别检查
ORA-01403(无数据)和ORA-02292(子记录未删),前者可忽略,后者需先清理外键关联表 - 循环内不要用
EXIT直接跳出,应设标志位并确保最终COMMIT或ROLLBACK
MAX(id) 作下一批起点,但并发插入可能导致新 id 被跳过;更稳的方式是用 FOR UPDATE SKIP LOCKED 加行级锁,或直接切 ROWID 范围。











