Delete与Truncate操作对表大小及水位线的影响咨询
Delete vs Truncate:表大小和水位线的那些事儿
嘿,这个疑问在Oracle用户里真的挺普遍的,我来给你拆解清楚背后的逻辑,顺便把两种操作的核心差异讲明白。
为啥Truncate全表后,表大小还是0.0625MB?
你看到的这个0.0625MB(也就是64KB),其实是Oracle给表分配的**初始扩展段(initial extent)**的大小。这玩意儿是你创建表时Oracle就预先分配好的,用来作为表的“基础容器”,哪怕表里没数据,它也会一直存在——除非你把表删掉。
Truncate默认的行为(不带DROP STORAGE参数)只会重置水位线,不会回收这个初始扩展段:
- 标准
TRUNCATE TABLE命令只是把已分配的空间标记为“可复用”,但不会还给操作系统,所以dba_segments里的大小看起来没变。 - 就算你加了
DROP STORAGE参数,Oracle也只会回收后续分配的扩展段,初始的那个64KB还是会保留下来,因为Oracle需要一个最基础的段来维持表的存在。
Delete和Truncate的核心差异:表大小+水位线
1. 对水位线(High Water Mark, HWM)的影响
这是两者最关键的性能差异点:
- Delete:只是把数据标记为“已删除”,完全不会碰水位线。哪怕你删光了所有数据,后续全表扫描(比如
SELECT COUNT(*) FROM SALES_HISTORY)还是会扫到原来的水位线位置,速度根本提不上来。 - Truncate:直接把水位线拉回表的起始位置。之后的全表扫描只会扫到新的水位线,性能会明显变好,因为跳过了之前那些空的、被标记为删除的空间。
2. 对表段大小(dba_segments.bytes)的影响
- Delete:半点儿空间都不会还给操作系统,
dba_segments里的大小和删之前一模一样。这些空出来的空间只能给同一张表的新数据用,其他表碰都碰不到——除非你手动执行ALTER TABLE SALES_HISTORY SHRINK SPACE;来收缩段,把空间还给表空间。 - Truncate:
- 默认模式:保留所有已分配的扩展段,大小不变,但这些空间会被标记为可复用,新插数据直接用,不用重新分配。
- 带
DROP STORAGE:回收除初始扩展段外的所有空间,此时表大小会降到初始的64KB(就是你看到的0.0625MB)。要是想彻底把这64KB也释放,只能删表重建,或者试试ALTER TABLE SALES_HISTORY DEALLOCATE UNUSED KEEP 0;(不过这个操作在部分Oracle版本里对初始扩展段无效)。
3. 其他你得知道的差异
- 事务性:Delete是DML操作,删完可以回滚;Truncate是DDL操作,执行完直接提交,根本没法回滚。
- 触发器:Delete会触发表上的DELETE触发器;Truncate完全不会触发任何DML触发器。
给你几个验证命令
你可以跑这些SQL来确认我说的内容:
- 查看表的扩展段详情:
你会看到只有一个extent,大小正好是64KB,就是那个初始扩展段。SELECT extent_id, bytes/1024 AS kb_size FROM dba_extents WHERE segment_name = 'SALES_HISTORY' AND owner = YOUR_USER_NAME; -- 替换成你的用户名 - 试试带
DROP STORAGE的Truncate:
再查TRUNCATE TABLE SALES_HISTORY DROP STORAGE;dba_segments,大小还是64KB,因为初始段没被回收。 - 要彻底释放空间?只能删表:
这时候再查DROP TABLE SALES_HISTORY;dba_segments,就找不到这个表的记录了。
内容的提问来源于stack exchange,提问作者Mansi Raval




