TRUNCATE TABLE几乎不写Redo,因其仅记录段头重置等元数据操作,而非逐行删除日志;5000万行仅生成几KB Redo,远少于DELETE的海量日志。
TRUNCATE TABLE 是唯一能真正绕过 Redo 日志、秒级清空大表的原生命令
,前提是你要清空整张表,且不依赖事务回滚、不触发 DELETE 触发器、也不需要保留自增序列当前值。
TRUNCATE TABLE 为什么几乎不写 Redo?
它不是逐行删除,而是直接释放数据段(data segment)和重置高水位线(HWM)。Oracle 只在 Redo 中记录“段头被重置”这一条元数据操作,而非每行数据的删除动作。所以哪怕删 5000 万行,Redo 体积也基本固定在几 KB 级别。
对比
:每删一行都生成 Undo + Redo 条目,5000 万行可能产生几十 GB Redo,还容易撑爆 UNDO 表空间或触发归档风暴。
必须用
,不能写成
或
(缺少
关键字会报错
)
执行用户需是表所有者,或拥有
或
权限
若表被外键引用,需先禁用约束(
),或加
子句(Oracle 12c+ 支持:
)
TRUNCATE 后序列(SEQUENCE)值被重置,怎么补救?
是的,
会把关联的
列或手动维护的序列计数器“打回原形”,从初始值(如 1)重新开始。这不是 Bug,是设计行为。
oracle知识库
oracle知识库下载
下载
如果你依赖序列值连续或不重用,不能靠
。此时只能退回到
+ 手动
,但代价是性能暴跌。
查当前最大 ID:
重设序列:
(注意:12cR2+ 才支持
;老版本用
+
+ 再改回步长)
但请再确认一次:你真的需要保留这个序列值?多数业务场景下,ID 唯一性比连续性重要得多
批量清空多个表时,PL/SQL 循环里要注意什么?
别手写一堆
—— 遇到权限不足或表不存在就中断。用动态 SQL + 异常捕获更稳:
务必用
或
过滤真实存在的表,避免
不要在循环里漏掉
——
是 DDL,自动提交,无需也不该手动加
如果某张表有未提交的事务锁住,
会直接报
,得先 kill 对应 session
真正容易被忽略的是权限粒度和外键联动——很多人卡在
或
上,却以为是命令写错了。其实问题不在
本身,而在它暴露了对象可见性与约束拓扑的真实状态。
DELETE FROM table_nameTRUNCATE TABLETRUNCATETRUNCATE tableTABLEORA-00900: invalid SQL statementALTER ANY TABLEDROP ANY TABLEALTER TABLE child_table DISABLE CONSTRAINT fk_nameCASCADETRUNCATE TABLE parent_table CASCADETRUNCATE TABLEIDENTITYTRUNCATEDELETEALTER SEQUENCE RESTART START WITH NSELECT NVL(MAX(id), 0) FROM your_tableALTER SEQUENCE your_seq RESTART START WITH 1234567RESTARTINCREMENT BYNEXTVALTRUNCATE TABLE t1; TRUNCATE TABLE t2;DECLARE
v_sql VARCHAR2(200);
BEGIN
FOR r IN (SELECT table_name FROM user_tables WHERE tablespace_name = 'USERS') LOOP
v_sql := 'TRUNCATE TABLE ' || r.table_name;
BEGIN
EXECUTE IMMEDIATE v_sql;
DBMS_OUTPUT.PUT_LINE('Truncated: ' || r.table_name);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Skip ' || r.table_name || ': ' || SQLERRM);
END;
END LOOP;
END;user_tablesdba_tablesORA-00942: table or view does not existCOMMITTRUNCATETRUNCATEORA-00054: resource busyORA-00942ORA-02266TRUNCATE