TRUNCATE TABLE in Oracle Datenbanken: Freigabe von Speicher - Neues in 11.2.0.2
Ralf Durben, 24.09.2010
Ein TRUNCATE TABLE Kommando löscht zwar Zeilen aus einer Tabelle (und zwar alle!), ist dem DELETE Kommando aber nicht gleich gestellt. So werden zum Beispiel auch keine DELETE-Trigger ausgelöst. Der Grund dafür ist recht einfach: Ein TRUNCATE TABLE Kommando erklärt einfach den gesamten für diese Tabelle allokierten Speicher zum Freispeicher, nach dem Motto "Das was dort noch gespeichert ist, das kenne ich nicht". Die einzelnen Datenzeilen werden also gar nicht einzeln betrachtet und deswegen ist das TRUNCATE Kommando auch so schnell.
In der Ursprungsvariante blieb ein Teil des Speichers für die leere Tabelle allokiert und der Rest wurde freigegeben. Das Verhalten kann sehr leicht über die Data Dictionary View DBA_EXTENTS ermittelt werden:
create table wdg (nr number,text varchar2(100))
/
begin
for i in 1..3000 loop
insert into wdg values (i,'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq');
commit;
end loop;
end;
/
select * from dba_extents where segment_name='WDG'
/
OWNER SEGMEN PARTITION_NAME SEGMENT TABLESP EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
------ ------ -------------- ------- ------- ---------- ---------- ---------- ---------- ---------- ------------
TT WDG TABLE USERS 0 4 488 65536 8 4
TT WDG TABLE USERS 1 4 496 65536 8 4
TT WDG TABLE USERS 2 4 504 65536 8 4
TT WDG TABLE USERS 3 4 512 65536 8 4
TT WDG TABLE USERS 4 4 520 65536 8 4
TT WDG TABLE USERS 5 4 528 65536 8 4
6 rows selected.
truncate table wdg
/
select * from dba_extents where segment_name='WDG'
/
OWNER SEGMEN PARTITION_NAME SEGMENT TABLESP EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
------ ------ -------------- ------- ------- ---------- ---------- ---------- ---------- ---------- ------------
TT WDG TABLE USERS 0 4 488 65536 8 4
In dieser ersten Variante des TRUNCATE TABLE Kommandos wurden also alle Extents (so werden die einzelnen Speicherstücke für ein Segment in einer Oracle Datenbank genannt), bis auf das erste, deallokiert. Das Ergebnis dieses Kommandos war demnach immer eine leere Tabelle mit einem leeren aber allokierten ersten Extent.
Dieses ist aber nicht günstig, wenn man weiss, dass in naher Zukunft wieder massiv Daten in diese Tabelle eingeladen werden. Daher wurde vor geraumer Zeit die Variante eingeführt, dass der Speicher allokiert bleibt, als Freispeicher für diese Tabelle. Für neue Datenlade-Vorgänge ist also keine Speicherallokierung notwendig. Im Beispiel sieht das dann so aus:
create table wdg (nr number,text varchar2(100))
/
begin
for i in 1..3000 loop
insert into wdg values (i,'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq');
commit;
end loop;
end;
/
select * from dba_extents where segment_name='WDG'
/
OWNER SEGMEN PARTITION_NAME SEGMENT TABLESP EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
------ ------ -------------- ------- ------- ---------- ---------- ---------- ---------- ---------- ------------
TT WDG TABLE USERS 0 4 488 65536 8 4
TT WDG TABLE USERS 1 4 496 65536 8 4
TT WDG TABLE USERS 2 4 504 65536 8 4
TT WDG TABLE USERS 3 4 512 65536 8 4
TT WDG TABLE USERS 4 4 520 65536 8 4
TT WDG TABLE USERS 5 4 528 65536 8 4
6 rows selected.
truncate table wdg reuse storage
/
select * from dba_extents where segment_name='WDG'
/
OWNER SEGMEN PARTITION_NAME SEGMENT TABLESP EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
------ ------ -------------- ------- ------- ---------- ---------- ---------- ---------- ---------- ------------
TT WDG TABLE USERS 0 4 488 65536 8 4
TT WDG TABLE USERS 1 4 496 65536 8 4
TT WDG TABLE USERS 2 4 504 65536 8 4
TT WDG TABLE USERS 3 4 512 65536 8 4
TT WDG TABLE USERS 4 4 520 65536 8 4
TT WDG TABLE USERS 5 4 528 65536 8 4
6 rows selected.
Alle Extents sind also weiterhin der Tabelle WDG zugeordnet und können ohne Neuallokierung für neue Daten verwendet werden.
Es gibt aber auch Fälle, in denen man möglichst alle Extents freigeben möchte um Speicherplatz zu sparen. Für diese Fälle bietet Oracle Database 11.2.0.2 eine neue Syntax: TRUNCATE TABLE ... DROP ALL STORAGE, wie das Beispiel zeigt:
create table wdg (nr number,text varchar2(100))
/
begin
for i in 1..3000 loop
insert into wdg values (i,'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq');
commit;
end loop;
end;
/
select * from dba_extents where segment_name='WDG'
/
OWNER SEGMEN PARTITION_NAME SEGMENT TABLESP EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
------ ------ -------------- ------- ------- ---------- ---------- ---------- ---------- ---------- ------------
TT WDG TABLE USERS 0 4 488 65536 8 4
TT WDG TABLE USERS 1 4 496 65536 8 4
TT WDG TABLE USERS 2 4 504 65536 8 4
TT WDG TABLE USERS 3 4 512 65536 8 4
TT WDG TABLE USERS 4 4 520 65536 8 4
TT WDG TABLE USERS 5 4 528 65536 8 4
6 rows selected.
truncate table wdg drop all storage
/
select * from dba_extents where segment_name='WDG'
/
no rows selected
Beim Einfügen neuer Daten werden notwendige Extents neu allokiert. Die neue Syntax funktioniert für normale Tabellen und Partitionen, jedoch nicht für Cluster-Tabellen: Ein TRUNCATE CLUSTER ... DROP ALL STORAGE funktioniert demnach nicht!
Im Falle der Partitionen wird das TRUNCATE im Rahmen des ALTER TABLE Kommandos angewendet:
alter table wdg truncate partition p1 drop all storage
/
|