LLL的数据库培训-77-第五部分—Oracle11g-Oracle SQL对象管理—第4讲—高水位
一、数据块结构
1、Database Block(数据库块)
- 最小单位的输入/输出;
- 数据块由操作系统中的一个或多个块组成;
- 数据块是表空间的基本单位;
- DB_BLOCK_SIZE 文件来表示缺省块的大小;
- 查看oracle 块的大小:SQL> show parameter db_block_size;
2、数据块的发展
- 在早期的数据库中, oracle 只支持一种数据块的大小。
- 从 9i 版本支持了改变大小的设置。
- 但也不是任用户随便改动的,规定范围在 2KB 到 32KB 之间,必须是倍数增加的,也就是2KB\4KB\8KB\16KB\32KB 五种大小。
- 需要注意的是,块大小的设置是在数据库创建时候设置的,一旦设置好是不可更改的。
- 类似于我们磁盘的存储格式, FAT16、 FAT32、 NTFS.... ,要想改变存储格式只能数数据全部格式化掉
3、块的描述
Hearder : 块头记录一些控制信息,帮助 oracle 定位这个块,块与块之间的串联信息。
Free space :处于重现状态的这空间。
Data :已经写入数据的空间。数据存放数据的方式是自底往上的,就像现实中的一个箱子。
4、高水位、低水位
(1)什么是水位
- 对一一个新建立的表,表中包含很多数据块, water mark 原始指向表中的第一个数据块。
- water mark 随着插入的数据“向前”移动。
- 当把插入的数据删除掉一些, water mark 并不会“向后”移动。
- 也就是 water mark 的位置表示历史的最高水位。
(2)那么我们要想插入一些数据时, oralce 是按什么样的规则输选择插入位置呢?
首先会先查找灰色的,灰色部分表示就已经插入数据的块,但这些块并不是已经被完全占满了,有些或多或少的都会留下一些空间。
--如果插入一个很小的数据,灰色被占的数据块中可以完全插入的,就会被插在这一部分。 --如果数据比较大,查找了所有被占用块都无法插入,那么将会选择“曾经” 插入过数据的空白块(上图)进行插入,也就是下图浅灰色部分。 --如果数据非常大,曾经插入数据的空白块都无法插入,那么只好动用从未被插入过数据的空白块(下图)进行插入。当然 water mark 也就会“向前”移动。
5、允许插入数据的规则
- 块头(数据块的头)不在百分比的范围内;
- 当剩余空间大于 20%的时候,这个块如果在freelist 中,当要插入一条数据时, freelist 是会扫描这个块的,检查其它是否可以存放要插入的数据。
- 当剩余空间小于 20%的时候,说明这个块已经满了,这个块会从 freelist 中去掉,插入数据时不作为扫描的对象。
- 一个小于 20%空闲的块会从 freelist 上摘除,那么一个块在什么情况下会被重新挂到 freelist上呢?
- 对于一个已经从 freelist 上摘除的块,可以能由于删除更新操作,其空间会得到释放。
- 当占用空间小于 40%时,也就是free空间大于 60%时,这个块被有认为是空间的块又会被重现挂到freelist 上
二、查看和调整高水位线标记及性能分析
1、什么是高水位线
在Oracle数据库中,高水位线(High Water Mark)是指数据段(segment)中已被分配但尚未被使用的空间的末端位置。它表示了数据段中最后一个有效数据块的位置。
当数据被插入、更新或删除时,高水位线会相应地移动。
高水位线的存在对于表的存储和性能都有影响。
当表中的数据被删除时,对应的数据块会变为未分配状态,但高水位线不会自动减小。因此,如果高水位线保持在一个较高的位置,会导致存储空间的浪费。
2、高水位线的作用
高水位线在Oracle中用于跟踪数据段中已分配但尚未使用的空间,并影响表的存储和性能。
通过适时调整高水位线,可以优化数据库的空间利用和性能。
3、高水位线的副作用(实验)
在执行查询命令时,Oracle有时需要扫描表中所有的数据块(高水位线以下)。这称为全表扫描。
如果已经从表中删除了大量数据,那么全表扫描就会花很多时间,即使表中一行数据也没有。
而且,在执行直接路径加载操作时,Oracle会将数据插入到高水位线标记上方的空间。当使用直接路径机制加载的数据被删除后,有可能会浪费表中的大量未使用空间。
4、如何查看高水位线
select count(*) from user_extents where segment_name='TEST'; select count(*) from test;
查看表的高水位线,示例:
SQL> analyze table test estimate statistics; SQL> select blocks,empty_blocks,num_rows from user_tables where table_name='TEST'; BLOCKS EMPTY_BLOCKS NUM_ROWS ---------- ------------ ---------- 30329 391 2010778
注:
BLOCKS:代表该表中曾经使用过的数据块的数量,即高水位线。
EMPTY_BLOCKS:代表分配给该表,但是在高水位线以上的数据块,即从来没有使用的数据块。
三、如何降低高水位线-方法有多种
1、move表
(1)查看当前高水位线
SQL> analyze table test estimate statistics; SQL> select blocks,empty_blocks,num_rows from user_tables where table_name='BIG_TABLE';
(2)move表之前,查看表上是否存在索引
SQL> select index_name,table_name,table_owner from dba_indexes where table_name='TEST';
(3)如存在索引,move表后需重建索引(可选)
SQL> alter index <index_name> rebuild;
(4)进行move
(可以在当前表空间或其他表空间之间进行移动)
SQL> alter table test move;
(5)释放后的高水位线
SQL> analyze table test estimate statistics; SQL> select blocks,empty_blocks,num_rows from user_tables where table_name='TEST';
2、收缩表
(1)查看当前高水位线
SQL> analyze table test estimate statistics; SQL> select blocks,empty_blocks,num_rows from user_tables where table_name='TEST';
BLOCKS EMPTY_BLOCKS NUM_ROWS ---------- ------------ ---------- 30329 391 2010778
(2)开启行移动和并行
--查看当前并行:
SQL> select OWNER,TABLE_NAME,DEGREE from DBA_TABLES where OWNER ='TEST' and TABLE_NAME = 'BIG_TABLE'; OWNER TABLE_NAME DEGREE --------- ------------ --------- TEST TEST DEFAULT
--设置并行:
alter table test.test parallel 2;
--开启行移动:
alter table test.test enable row movement;
(3)检查表能否被收缩
SQL> alter table test.test shrink space check; alter table test.test shrink space check * ERROR at line 1: ORA-10655: Segment can be shrunk ---表示可以进行表收缩
(4)收缩表数据
SQL> alter table test.test shrink space compact;
(5)降低高水位线
SQL> alter table test.test shrink space;
(6)收缩索引
SQL> alter table test.test shrink space cascade;
(7)释放后的高水位线
SQL> analyze table test estimate statistics; SQL> select blocks,empty_blocks,num_rows from user_tables where table_name='TEST';
BLOCKS EMPTY_BLOCKS NUM_ROWS --------- ------------ ---------- 14984 168 1002139
(8)禁用行移动和并行
SQL> alter table test.teset disable row movement; SQL> alter table test.test parallel 1; SQL> alter table test.test parallel;
3、数据泵导出导入重构表
(1)查看当前高水位线
SQL> analyze table test estimate statistics; SQL> select blocks,empty_blocks,num_rows from user_tables where table_name='TEST';
BLOCKS EMPTY_BLOCKS NUM_ROWS ---------- ------------ ---------- 30329 391 2010778
(2)对表进行导出操作
expdp \'/ as sysdba\' directory=dir dumpfile=test.dmp logfile=table.log schemas=test tables=big_table
(3)删除表
SQL> drop table test purge;
(4)导入表
impdp \'/ as sysdba\' directory=dir dumpfile=test.dmp logfile=table2.log tables=test.test
(5)释放后的高水位线
SQL> analyze table test estimate statistics; SQL> select blocks,empty_blocks,num_rows from user_tables where table_name='TEST';
BLOCKS EMPTY_BLOCKS NUM_ROWS --------- ------------ ---------- 14988 372 1010535
4、复制表数据的方式
(也就是将保留的数据复制到新表,drop原表,最后将新表rename为原表的方式)
(1)查看当前高水位线
SQL> analyze table big_table estimate statistics; SQL> select blocks,empty_blocks,num_rows from user_tables where table_name='BIG_TABLE';
BLOCKS EMPTY_BLOCKS NUM_ROWS ---------- ------------ ---------- 30329 391 2010778
(2)创建新表
SQL> create table copy_test as select * from test;
(3)drop原表
SQL> drop table test purge;
(4)rename新表
SQL> alter table copy_test rename to test;
(5)释放后的高水位线
SQL> analyze table test estimate statistics; SQL> select blocks,empty_blocks,num_rows from user_tables where table_name='TEST'; BLOCKS EMPTY_BLOCKS NUM_ROWS ---------- ------------ ---------- 14998 362 1010504
5、truncate
(仅在表中没有数据的情况下使用,谨慎使用)
(1)查看当前高水位线
SQL> analyze table test estimate statistics; SQL> select blocks,empty_blocks,num_rows from user_tables where table_name='BIG_TABLE';
BLOCKS EMPTY_BLOCKS NUM_ROWS ---------- ------------ ---------- 30329 391 2010778
(2)删除表中的所有数据
SQL> delete test where id>0; 2000000 rows deleted. SQL> commit; Commit complete.
(3)在表中没有数据的情况下,执行 truncate 来释放高水位线
SQL> truncate table test;
(4)释放后的高水位线
SQL> analyze table test estimate statistics; SQL> select blocks,empty_blocks,num_rows from user_tables where table_name='TEST'; BLOCKS EMPTY_BLOCKS NUM_ROWS --------- ------------ ---------- 0 8 0