用Delete与Truncate清除表数据对高水位的影响

众所周知,oracle段都有一个在段内容纳数据块的上限,我们把这个上限称为"High Water Mark"(HWM)。这个HWM是一个标记,用来说明已经有多少没有使用的数据块分配给这个segment。原则上HWM只会增大,不会缩小,即使将表中的数据全部删除,HWM还是为原值。HWM就像一个水库的历史最高水位,这也是为何会称之为“高水位”的缘故。实际环境中随着我们表中数据的不断增长,表的高水位也被不断的推高。当高水位达到一定程度之后,会对该表上的SQL查询效率产生负面影响,因此需要采取有效措施降低高水位。下面做个测试,来比较下如何删除数据才能有效降低高水位。注意,我的测试环境为11.2.0.3,其他版本的测试结果未必会完全相同。

--创建测试环境

SQL> conn / as sysdba

SQL> create tablespace zlm datafile ‘/u01/app/oracle/oradata/zlm11g/zlm01.dbf‘ size 50m;

Tablespace created.

SQL> create table zlm.zlm1 as select * from dba_objects;

Table created.

SQL> set lin 130 pages 130

SQL> select table_name,num_rows,blocks,empty_blocks,avg_row_len,last_analyzed from dba_tables where table_name like ‘ZLM%‘;

TABLE_NAME                       NUM_ROWS     BLOCKS EMPTY_BLOCKS AVG_ROW_LEN LAST_ANALYZED

------------------------------ ---------- ---------- ------------ ----------- ------------------

ZLM1

--分析表的统计信息

SQL> analyze table zlm.zlm1 estimate statistics;

Table analyzed.

SQL> select table_name,num_rows,blocks,empty_blocks,avg_row_len,last_analyzed from dba_tables where table_name like ‘ZLM%‘;

TABLE_NAME                       NUM_ROWS     BLOCKS EMPTY_BLOCKS AVG_ROW_LEN LAST_ANALYZED

------------------------------ ---------- ---------- ------------ ----------- ------------------

ZLM1                                77341       1101           51         100 27-SEP-14

SQL> select count(*) from zlm.zlm1;

SQL> select count(*) from zlm.zlm1;

COUNT(*)

----------

75541

可以看到,用estimate分析的表的行数会不准确,差了1800条记录,我们用compute来分析表

SQL> analyze table zlm.zlm1 compute statistics;

Table analyzed.

SQL> select table_name,num_rows,blocks,empty_blocks,avg_row_len,last_analyzed from dba_tables where table_name like ‘ZLM%‘;

TABLE_NAME                       NUM_ROWS     BLOCKS EMPTY_BLOCKS AVG_ROW_LEN LAST_ANALYZED

------------------------------ ---------- ---------- ------------ ----------- ------------------

ZLM1                                75541       1101           51         100 27-SEP-14

也可以用dbms_stats包来收集表的统计信息

SQL> exec dbms_stats.gather_table_stats(‘ZLM‘,‘ZLM1‘)

PL/SQL procedure successfully completed.

SQL> select table_name,num_rows,blocks,empty_blocks,avg_row_len,last_analyzed from dba_tables where table_name like ‘ZLM%‘;

TABLE_NAME                       NUM_ROWS     BLOCKS EMPTY_BLOCKS AVG_ROW_LEN LAST_ANALYZED

------------------------------ ---------- ---------- ------------ ----------- ------------------

ZLM1                                75541       1101           51          97 27-SEP-14

对于普通表而言,用dbms_stats包和用analyze来收集统计信息区别不大,但这两种方法还是有各自应用场景的:

1、对于分区表,建议使用DBMS_STATS,而不是使用Analyze语句。

a) 可以并行进行,对多个用户,多个Table

b) 可以得到整个分区表的数据和单个分区的数据。

c) 可以在不同级别上Compute Statistics:单个分区,子分区,全表,所有分区

d) 可以倒出统计信息

e) 可以用户自动收集统计信息

2、DBMS_STATS的缺点

a) 不能Validate Structure

b) 不能收集CHAINED ROWS, 不能收集CLUSTER TABLE的信息,这两个仍旧需要使用Analyze语句。

c) DBMS_STATS 默认不对索引进行Analyze,因为默认Cascade是False,需要手工指定为True

3、对于oracle 9里面的External Table,Analyze不能使用,只能使用DBMS_STATS来收集信息。

SQL> select header_file,header_block,bytes,blocks,extents from dba_segments where segment_name like ‘ZLM%‘;

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

----------- ------------ ---------- ---------- ----------

6          130    9437184       1152         24

这里我们发现,在dba_tables中占用的块为1101+52=1152,其中1152就是我们的高水位,EMPTY_BLOCKS表示高水位以下未被使用的空块,

我们可以通过show_space()存储过程来验证一下:

SQL> exec show_space(‘ZLM1‘,‘ZLM‘)

Total Blocks............................1152

Total Bytes.............................9437184

Unused Blocks...........................51

Unused Bytes............................417792

Last Used Ext FileId....................6

Last Used Ext BlockId...................1152

Last Used Block.........................77

PL/SQL procedure successfully completed.

--查看测试表ZLM1占用extent和block的情况

SQL> select block_id,extent_id,bytes,blocks from dba_extents where segment_name like ‘ZLM%‘;

BLOCK_ID  EXTENT_ID      BYTES     BLOCKS

---------- ---------- ---------- ----------

128          0      65536          8

136          1      65536          8

144          2      65536          8

152          3      65536          8

160          4      65536          8

168          5      65536          8

176          6      65536          8

184          7      65536          8

192          8      65536          8

200          9      65536          8

208         10      65536          8

216         11      65536          8

224         12      65536          8

232         13      65536          8

240         14      65536          8

248         15      65536          8

256         16    1048576        128    --从256块起,开始分配1M的空间作为1个extent

384         17    1048576        128

512         18    1048576        128

640         19    1048576        128

768         20    1048576        128

896         21    1048576        128

1024         22    1048576        128

1152         23    1048576        128

从block_id字段的值可以发现,当在表插入数据后,分配给表的block从128开始一直到1152,并且,开始的1-16个extent会以8个块(8*8=64K)为分配单位,而到了第17个extent之后,则以128个块(8*128=1M)为分配单位,目前ZLM1表共分配了24个extent

--查看测试表ZLM1的block分配情况

SQL> col segment_name for a10

SQL> select segment_name,header_file,header_block,blocks,bytes,extents,min_extents,max_extents,segment_type from dba_segments where segment_name like ‘ZLM%‘;

SEGMENT_NA HEADER_FILE HEADER_BLOCK     BLOCKS      BYTES    EXTENTS MIN_EXTENTS MAX_EXTENTS SEGMENT_TYPE

---------- ----------- ------------ ---------- ---------- ---------- ----------- ----------- ------------------

ZLM1                 6          130       1152    9437184         24           1  2147483645 TABLE

这里可以发现一个规律,dba_segments中的header_block的值总是要比dba_extents查出来值的多2个块

--创建测试表ZLM2并查看block分配情况

SQL> create table zlm.zlm2 as select * from zlm.zlm1;

Table created.

SQL>  select segment_name,header_file,header_block,blocks,bytes,extents,min_extents,max_extents,segment_type from dba_segments where segment_name like ‘ZLM%‘;

SEGMENT_NA HEADER_FILE HEADER_BLOCK     BLOCKS      BYTES    EXTENTS MIN_EXTENTS MAX_EXTENTS SEGMENT_TYPE

---------- ----------- ------------ ---------- ---------- ---------- ----------- ----------- ------------------

ZLM2                 6         1282       1152    9437184         24           1  2147483645 TABLE

ZLM1                 6          130       1152    9437184         24           1  2147483645 TABLE

第2个表从1282个块开始分配,为什么是1282呢?1282=130+1152,也就是从测试表ZLM1之后的block开始分配

--delete测试表ZLM1中的数据

SQL> delete from zlm.zlm1;

75541 rows deleted.

SQL> commit;

Commit complete.

SQL> select table_name,num_rows,blocks,empty_blocks,avg_row_len,last_analyzed from dba_tables where table_name like ‘ZLM%‘;

TABLE_NAME                       NUM_ROWS     BLOCKS EMPTY_BLOCKS AVG_ROW_LEN LAST_ANALYZED

------------------------------ ---------- ---------- ------------ ----------- ------------------

ZLM1                                75541       1101           51         100 27-SEP-14

--分析测试表ZLM1和ZLM2并查看各自数据块占用情况

SQL> analyze table zlm.zlm1 compute statistics;

Table analyzed.

SQL> analyze table zlm.zlm2 compute statistics;

Table analyzed.

SQL> select table_name,num_rows,blocks,empty_blocks,avg_row_len,last_analyzed from dba_tables where table_name like ‘ZLM%‘;

TABLE_NAME                       NUM_ROWS     BLOCKS EMPTY_BLOCKS AVG_ROW_LEN LAST_ANALYZED

------------------------------ ---------- ---------- ------------ ----------- ------------------

ZLM1                                    0       1101           51           0 27-SEP-14

ZLM2                                75541       1101           51         100 27-SEP-14

删除ZLM1表中数据以后,NUM_ROWS值为0,但是还是占用了1152个数据块,说明此时高水位并没有下降,仍然为1152

--truncate测试表ZLM1

SQL> truncate table zlm.zlm1;

Table truncated.

SQL> select segment_name,header_file,header_block,blocks,bytes,extents,min_extents,max_extents,segment_type from dba_segments where segment_name like ‘ZLM%‘;

SEGMENT_NA HEADER_FILE HEADER_BLOCK     BLOCKS      BYTES    EXTENTS MIN_EXTENTS MAX_EXTENTS SEGMENT_TYPE

---------- ----------- ------------ ---------- ---------- ---------- ----------- ----------- ------------------

ZLM2                 6         1282       1152    9437184         24           1  2147483645 TABLE

ZLM1                 6          130          8      65536          1           1  2147483645 TABLE

用truncate清空表数据之后,高水位立即下降到8了,8个block共占用64k,1个extent

--重新分析测试表ZLM2并查看数据块占用情况

SQL>  analyze table zlm.zlm1 compute statistics;

Table analyzed.

SQL> select table_name,num_rows,blocks,empty_blocks,avg_row_len,last_analyzed from dba_tables where table_name like ‘ZLM%‘;

TABLE_NAME                       NUM_ROWS     BLOCKS EMPTY_BLOCKS AVG_ROW_LEN LAST_ANALYZED

------------------------------ ---------- ---------- ------------ ----------- ------------------

ZLM2                                75541       1101           51         100 27-SEP-14

ZLM1                                    0          0            8           0 27-SEP-14

--查看数据块和extent分布情况

SQL> select block_id,extent_id,bytes,blocks from dba_extents where segment_name like ‘ZLM1‘;

BLOCK_ID  EXTENT_ID      BYTES     BLOCKS

---------- ---------- ---------- ----------

128          0      65536          8

可以看到,虽然测试表ZLM1中已经没有数据,但是还是会占用8个数据块的高水位,也就是说,当你创建一个空表,即只建立表结构的时候,Oracle就会给这个表分配至少一个extent,默认为8,可以通过参数调整这个默认值

SQL> select block_id,extent_id,bytes,blocks from dba_extents where segment_name like ‘ZLM2‘;

BLOCK_ID  EXTENT_ID      BYTES     BLOCKS

---------- ---------- ---------- ----------

1280          0      65536          8

1288          1      65536          8

1296          2      65536          8

1304          3      65536          8

1312          4      65536          8

1320          5      65536          8

1328          6      65536          8

1336          7      65536          8

1344          8      65536          8

1352          9      65536          8

1360         10      65536          8

1368         11      65536          8

1376         12      65536          8

1384         13      65536          8

1392         14      65536          8

1400         15      65536          8

1408         16    1048576        128

1536         17    1048576        128

1664         18    1048576        128

1792         19    1048576        128

1920         20    1048576        128

2048         21    1048576        128

2176         22    1048576        128

2304         23    1048576        128

--创建测试表ZLM3并插入数据查看数据块分配情况

SQL> create table zlm.zlm3 as select * from zlm.zlm2;

Table created.

SQL> select segment_name,header_file,header_block,blocks,bytes,extents,min_extents,max_extents,segment_type from dba_segments where segment_name like ‘ZLM%‘;

SEGMENT_NA HEADER_FILE HEADER_BLOCK     BLOCKS      BYTES    EXTENTS MIN_EXTENTS MAX_EXTENTS SEGMENT_TYPE

---------- ----------- ------------ ---------- ---------- ---------- ----------- ----------- ------------------

ZLM3                 6          138       1152    9437184         24           1  2147483645 TABLE

ZLM2                 6         1282       1152    9437184         24           1  2147483645 TABLE

ZLM1                 6          130          8      65536          1           1  2147483645 TABLE

SQL> select block_id,extent_id,bytes,blocks from dba_extents where segment_name like ‘ZLM3‘;

BLOCK_ID  EXTENT_ID      BYTES     BLOCKS

---------- ---------- ---------- ----------

136          0      65536          8

144          1      65536          8

152          2      65536          8

160          3      65536          8

168          4      65536          8

176          5      65536          8

184          6      65536          8

192          7      65536          8

200          8      65536          8

208          9      65536          8

216         10      65536          8

224         11      65536          8

232         12      65536          8

240         13      65536          8

248         14      65536          8

256         15      65536          8

384         16    1048576        128

512         17    1048576        128

640         18    1048576        128

768         19    1048576        128

896         20    1048576        128

1024         21    1048576        128

1152         22    1048576        128

2432         23    1048576        128

在降低了测试表空间中的高水位后,新创建的表会从第138块开始分配header_block空间,而不是1282+1152=2434,注意这里header_block的值依然会比此表extent中分配的第一个block的值要大2,而2434-2正好等于2432,也就是该表分配到的最后一个extent中block的起始id,通过truncate,可以重新把原来应该由测试表ZLM1占用的那部分block空间释放出来,给测试表ZLM3的extent,用于分配block

总结:

本测试只是验证了delete和truncate对于高水位的影响,与减少磁盘碎片及空间释放的概念并不是很相关,其实用truncate降低高水位来释放磁盘空间的作用是很有限的,我们关注高水位的主要目的,不是去减少浪费磁盘空间,而是出于性能上的考虑,由于高水位的存在,一旦对表做全表扫描,就会使性能大大降低,即使只是一张空的表,如果要真正减少表空间碎片,减少磁盘占用空间,更有效的方法是使用move或shrink(10g
or higher),甚至expdp导出再impdp倒入等方法,这里就不一一举例了,当然了,这些方法也都是降低高水位的有效手段。

时间: 2024-10-12 15:48:02

用Delete与Truncate清除表数据对高水位的影响的相关文章

Oracle快速清除表数据

Oracle快速清除表数据 一:简介 删除表数据一般常用的有三种命令.truncate.delete.drop.但是他们的执行方式.效率和结果各有不同.比如删除500W记录级别的数据时.三者之间有很大的不同. 二:truncate delete drop 三者都用可以用于清除表数据.其相似与不同之处如下 相同点: 1.truncate和不带where子句的delete.以及drop都会删除表内的数据. 2.drop.truncate都是DDL语句(数据定义语言),执行后会自动提交. 不同点: 1

3.数据库操作相关术语,Oracle认证,insert into,批量插入,update tablename set,delete和truncate的区别,sql文件导入

 1相关术语 语句 含义 操作 DML语句 (Data Manipulation Language) 数据库操作语言 insert update delete select DDL语言 (Date definition Language) 数据库定义语言 create table;create view index sequence synonvm同义词,truncate table DCL语言 (Data control Language) 数据控制语言 commit rollback s

TRUNCATE 删除表,无法回退。默认选择为整个表的内容,所以不能加条件。

TRUNCATE 删除表,无法回退.默认选择为整个表的内容,所以不能加条件.DELETE 删除表,可以回退.可以带where 条件.建议使用delete.但是TRUNCATE 删除表数据比delete要快. 使用TRUNCATE TABLE语句 TRUNCATE TABLE语句提供了一种删除表中所有记录的快速方法.因为TRUNCATE TABLE语句不记录日志,只记录整个数据页的释放操作,而DELETE语句对每一行修改都记录日志,所以使用TRUNCATE TABLE语句进行删除操作总是比没有指定

使用达思SQL数据库修复软件导出数据库时的接收数据的数据库如何清空表数据?

清空表数据,保留视图,存储过程,函数,以及保留表约束.触发器等等,可以给故障数据库预留一个好的躯壳,把坏库数据导入此躯壳.对用友.金蝶等数据库恢复有时候能达到好的效果. 清除表数据有两种方法: 一种用delete from [表名] ,这种方法对于大数据库,速度慢,会产生很大的日志信息,对于小库,速度可以忽略: 另一种是truncate table [表名] ,这种方法速度快,但清除不了具有外键的表数据. 在清除表数据时,可以采用两种方法结合. 清除表数据时先禁用一切约束,清除完成以后再次启用约

删除表和表数据

删除表的T-SQL语句为:drop table <表名>drop是丢弃的意思,drop table表示将一个表彻底删除掉. 删除表数据有两种方法:delete和truncate. delete的用法如下:delete from <表名> [where条件] truncate的用法如下:truncate table <表名> delete和truncate的区别如下:1.delete可以删除表中的一条或多条数据,也可以删除全部数据:而truncate只能将表中的全部数据删

SQL Server 如何清空数据库所有表数据

1.清空SQL Server数据库中所有表数据 (1)编写存储过程脚本: CREATE PROCEDURE sp_DeleteAllDataASEXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'EXEC sp_MSForEachTable 'ALTER TABLE ? DISABLE TRIGGER ALL'EXEC sp_MSForEachTable 'DELETE FROM ?'EXEC sp_MSForEachTabl

delete、truncate、drop区别

1.drop删除表数据和表结构,delete和truncate只删除表数据 2.delete逐行记录到redo日志中,可恢复,truncate和drop只记录少量操作语句,不能恢复. 3.delete可触发trigger,truncate不能 4.delete是DML语句,truncate.drop是DDL语句 5.执行速度drop>truncate>delete 6.truncate后,表和索引占用空间恢复到初始大小,delete后,表和索引空间不变,drop后,表和索引占用空间全部释放.

oracle删除表数据的两种的方式

转自:https://blog.csdn.net/qq_37840993/article/details/82490787 平时写sql中我们都会用到删除语句,而平时删除表数据的时候我们经常会用到两种方式: 在oracle中,truncate.delete都可以删除表数据,具体的区别以及sql语法如下: truncate table [表名]; delete from [表名]; delete与truncate的区别:delete:会产生rollback,如果删除大数据量的表速度会很慢,而且同时

特殊手段恢复被truncate的表

最近在写oracle抽取数据文件工具,在抽取数据文件恢复数据的时候发现,恢复的数据比预期的多,经过对比之后发现是有一些表被truncate了,由于被truncate之后部分块还没有被覆盖.所以这样的数据也就抽取出来了.其实抽取工具的原理就是根据段头.三级块位图.二级块位图.一级块位图等,再加上系统表空间对应的数据文件.最后整合之后就可以转换成表数据.1.创建测试数据 SQL> create tablespace py datafile '/u01/app/oradata/QXY/py.dbf'