众所周知,TRUNCATE TABLE是一种快速清空表内数据的一种方式,与delete方式不同,truncate只产生非常少的redo和undo,就实现了清空表数据并降低表HWM的功能。本文主要围绕TRUNCATE TABLE的实现原理和TRUNCATE TABLE的恢复来展开。
首先构造测试环境,并通过10046以及redo dump去分析truncate的整个操作过程。其中10046用于观察truncate对于字典基表的操作;redo dump用于观察truncate对于segment header以及L1、L2位图块的操作。
OS: redhat 6.5
db:11.2.0.4
基于assm
segment&extent info:
SYS@:>select owner,segment_name,header_file,header_block from dba_segments where segment_name='TRUNCATE_TABLE' and owner='TEST';OWNER SEGMENT_NAME HEADER_FILE HEADER_BLOCK
-------------------- -------------------- ----------- ------------
TEST TRUNCATE_TABLE 5 1898SYS@:>select extent_id,file_id,block_id,blocks from dba_extents where segment_name='TRUNCATE_TABLE' and owner='TEST' order by 1;EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------0 5 1896 81 5 12104 82 5 12112 83 5 12120 84 5 12128 85 5 12136 86 5 12144 87 5 12152 88 5 11904 89 5 11912 810 5 11920 811 5 11928 812 5 11936 813 5 11944 814 5 11952 815 5 11960 816 5 16256 12817 5 16384 12818 5 16512 12819 5 16768 12820 5 22528 12821 5 22656 12822 5 22784 12823 5 22912 12824 5 23040 12825 5 23168 12826 5 23296 12827 5 23424 128
通过10046和redo dump去观察truncate操作:
SYS@TEST(test):1>select count(*) from test.truncate_table;COUNT(*)
----------113426SYS@:>alter system flush SHARED_POOL;System altered.SYS@:>alter system flush BUFFER_CACHE;System altered.SYS@:>alter system switch logfile;System altered.SYS@:>select * from v$log;GROUP# THREAD# SEQUENCE# BYTES BLOCKSIZE MEMBERS ARC STATUS FIRST_CHANGE# FIRST_TIME NEXT_CHANGE# NEXT_TIME
---------- ---------- ---------- ---------- ---------- ---------- --- ---------------- ------------- ------------------ ------------ ------------------1 1 85 52428800 512 1 NO CURRENT 4116465 21-APR-18 2.8147E+142 1 83 52428800 512 1 NO INACTIVE 4092314 20-APR-18 4116301 21-APR-183 1 84 52428800 512 1 NO INACTIVE 4116301 21-APR-18 4116465 21-APR-18SYS@:>oradebug setmypid;
Statement processed.
SYS@:>oradebug tracefile_name
/u01/app/oracle/diag/rdbms/test/test/trace/test_ora_7091.trc
SYS@:>oradebug event 10046 trace name context forever,level 12;
Statement processed.
SYS@:>truncate table test.truncate_table;
Table truncated.
SYS@:>oradebug event 10046 trace name context off;
Statement processed.
SYS@TEST(test):1>alter system dump logfile '/u01/app/oracle/oradata/test/redo01.log';
System altered.
从10046 trace里搜出对基表的dml操作:
update:
[root@prim1-11g ~]# grep -i "^update" /u01/app/oracle/diag/rdbms/test/test/trace/test_ora_7091.trc
update obj$ set obj#=:4, type#=:5,ctime=:6,mtime=:7,stime=:8,status=:9,dataobj#=:10,flags=:11,oid$=:12,spare1=:13, spare2=:14 where owner#=:1 and name=:2 and namespace=:3 and remoteowner is null and linkname is null and subname is null
update sys.mon_mods$ set inserts = inserts + :ins, updates = updates + :upd, deletes = deletes + :del, flags = (decode(bitand(flags, :flag), :flag, flags, flags + :flag)), drop_segments = drop_segments + :dropseg, timestamp = :time where obj# = :objn
update tab$ set ts#=:2,file#=:3,block#=:4,bobj#=decode(:5,0,null,:5),tab#=decode(:6,0,null,:6),intcols=:7,kernelcols=:8,clucols=decode(:9,0,null,:9),audit$=:10,flags=:11,pctfree$=:12,pctused$=:13,initrans=:14,maxtrans=:15,rowcnt=:16,blkcnt=:17,empcnt=:18,avgspc=:19,chncnt=:20,avgrln=:21,analyzetime=:22,samplesize=:23,cols=:24,property=:25,degree=decode(:26,1,null,:26),instances=decode(:27,1,null,:27),dataobj#=:28,avgspc_flb=:29,flbcnt=:30,trigflag=:31,spare1=:32,spare2=decode(:33,0,null,:33),spare4=:34,spare6=:35 where obj#=:1
update seg$ set type#=:4,blocks=:5,extents=:6,minexts=:7,maxexts=:8,extsize=:9,extpct=:10,user#=:11,iniexts=:12,lists=decode(:13, 65535, NULL, :13),groups=decode(:14, 65535, NULL, :14), cachehint=:15, hwmincr=:16, spare1=DECODE(:17,0,NULL,:17),scanhint=:18, bitmapranges=:19 where ts#=:1 and file#=:2 and block#=:3
delete:
[root@prim1-11g ~]# grep -i "^delete" /u01/app/oracle/diag/rdbms/test/test/trace/test_ora_7091.trc
delete from superobj$ where subobj# = :1
delete from tab_stats$ where obj#=:1
对基表的修改主要是:
修改obj$,tab$的dataobj#
修改seg$的对应信息如(extents,blocks,hwmincr等等)
删除tab_stats$对应对象的统计信息
对于segment header以及L1、L2位图块的操作,只能通过redo dump去观察,因为在logminer中只会记录数据块的变更,而对于segment header和L1、L2位图块的操作在logminer里只记录操作类型为internal或者unsupported,没有什么有价值的信息。
通过对redo dump的分析,发现truncate操作只对segment header,L2位图块,第一个L1位图块和 HWM block所属的L1位图块进行了修改。
对于segment header:
修改块的dataobj#
修改LHWM和HHWM
修改extent map、aux map以及extents个数
对于L2位图块:
删除L1 ranges
修改L2块的dataobj#
对于第一个L1位图块:
修改第一个L1块的dataobj#
set hwm为ext#为0的第3+1个块(即段头块+1)
对于HWM block所属的L1位图块:
clear HWM flag
truncate的实质是在不修改数据块的情况下,通过修改segment header的data_object_id、hwm、extent map、aux map等信息来实现清空表的目的,其中还涉及数据字典基表以及L1、L2位图块的修改,所以说truncate操作只是存储数据的数据块没有产生任何redo和undo,但是segment header、位图块、数据字典基表还是会产生redo和undo。
关于作者
李翔宇,云和恩墨西区交付技术顾问,长期服务移动运营商行业客户,熟悉Oracle性能优化,故障诊断,特殊恢复。
今年的数据技术嘉年华大会上,李翔宇老师将带来题为《在通过案例深入解析Oracle内部原理》的演讲,与大家一起探索CBO和ASM rebalance的一些内部机制,精彩不容错过!
更多数据库行业相关内容,欢迎光临 2021 数据技术嘉年华 :https://www.modb.pro/dtc2021(扫描下方二维码免费领取大会门票)
END
推荐阅读:267页!2020年度数据库技术年刊
推荐下载:2020数据技术嘉年华PPT下载
2020数据技术嘉年华近50个PPT下载、视频回放已上传墨天轮平台,可在“数据和云”公众号回复关键词“2020DTC”获得!
你知道吗?我们的视频号里已经发布了很多精彩的内容,快去看看吧!↓↓↓
点击下图查看更多 ↓
云和恩墨大讲堂 | 一个分享交流的地方
长按,识别二维码,加入万人交流社群
请备注:云和恩墨大讲堂
点个“在看”
你的喜欢会被看到❤