oracle空间管理深入讲解
SQL> create table t1 as select * from dba_objects;
Table created.
SQL> select table_name,NUM_ROWS,blocks,EMPTY_BLOCKS,pct_free,pct_used from user_tables where table_name='T1';
TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS PCT_FREE PCT_USED
------------------------------ ---------- ---------- ------------ ---------- ----------
T1 10
SQL> ANALYZE TABLE T1 COMPUTE STATISTICS;
Table analyzed.
SQL> select table_name,NUM_ROWS,blocks,EMPTY_BLOCKS,pct_free,pct_used from user_tables where table_name='T1';
TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS PCT_FREE PCT_USED
------------------------------ ---------- ---------- ------------ ---------- ----------
T1 86310 1261 19 10
行迁移:
当一个行上的更新操作(原来的数据存在且没有减少)导致当前的数据不能在容纳在当前块,我们需要进行行迁移。一个行迁移意味着整行数据将会移动,仅仅保留的是一个转移地址。因此整行数据都被移动,原始的数据块上仅仅保留的是指向新块的一个地址信息。
迁移行对索引读产生额外的I/O
当我们根据地址信息达到所在位置时,从其转移地址得知,其真实的数据是存储在文件A,块B,slot槽C上。因此为了寻找该行数据不得不产生额外的逻辑或物理I/O。
行链接
当一行数据太大而不能在一个单数据块容纳时,行链接由此产生。举例来说,当你使用了4kb的Oracle数据块大小,而你需要插入一行数据是8k,Oracle则需要使用3个数据块分成片来存储。因此,引起行链接的情形通常是,表上行记录的大小超出了数据库Oracle块的大小
PCTFREE:为一个块保留的空间百分比,表示数据块在什么情况下可以被insert,默认是10,表示当数据块的可用空间低于10%后,就不可以被insert了,只能被用于update;即:当使用一个block时,在达到pctfree之前,该block是一直可以被插入的,这个时候处在上升期。
alter table t1 pctfree 20;
SQL> select table_name,NUM_ROWS,blocks,EMPTY_BLOCKS,pct_free,pct_used from user_tables where table_name='T1';
TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS PCT_FREE PCT_USED
------------------------------ ---------- ---------- ------------ ---------- ----------
T1 86310 1261 19 20
PCTUSED:是指当块里的数据低于多少百分比时,又可以重新被insert,一般默认是40,即40%,即:当数据低于40%时,又可以写入新的数据,这个时候处在下降期。
SQL> select segment_name,blocks from user_segments where segment_name='T1';
SEGMENT_NAME BLOCKS
--------------------------------------------------------------------------------- ----------
T1 1280
Oracle表段中的高水位线HWM
在Oracle数据的存储中,可以把存储空间想象为一个水库,数据想象为水库中的水。水库中的水的位置有一条线叫做水位线,在Oracle中,这条线被称为高水位线(High-warter mark, HWM)。在数据库表刚建立的时候,由于没有任何数据,所以这个时候水位线是空的,也就是说HWM为最低值。当插入了数据以后,高水位线就会上涨,但是这里也有一个特性,就是如果你采用delete语句删除数据的话,数据虽然被删除了,但是高水位线却没有降低,还是你刚才删除数据以前那么高的水位。也就是说,这条高水位线在日常的增删操作中只会上涨,不会下跌。
SQL> delete from t1;
86310 rows deleted.
SQL> commit;
Commit complete.
SQL> select table_name,NUM_ROWS,blocks,EMPTY_BLOCKS,pct_free,pct_used from user_tables where table_name='T1';
TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS PCT_FREE PCT_USED
------------------------------ ---------- ---------- ------------ ---------- ----------
T1 86310 1261 19 20
下面我们来谈一下Oracle中Select语句的特性。Select语句会对表中的数据进行一次扫描,但是究竟扫描多少数据存储块呢,这个并不是说数据库中有多少数据,Oracle就扫描这么大的数据块,而是Oracle会扫描高水位线以下的数据块。现在来想象一下,如果刚才是一张刚刚建立的空表,你进行了一次Select操作,那么由于高水位线HWM在最低的0位置上,所以没有数据块需要被扫描,扫描时间会极短。而如果这个时候你首先插入了一千万条数据,然后再用delete语句删除这一千万条数据。由于插入了一千万条数据,所以这个时候的高水位线就在一千万条数据这里。后来删除这一千万条数据的时候,由于delete语句不影响高水位线,所以高水位线依然在一千万条数据这里。这个时候再一次用select语句进行扫描,虽然这个时候表中没有数据,但是由于扫描是按照高水位线来的,所以需要把一千万条数据的存储空间都要扫描一次,也就是说这次扫描所需要的时间和扫描一千万条数据所需要的时间是一样多的。所以有时候有人总是经常说,怎么我的表中没有几条数据,但是还是这么慢呢,这个时候其实奥秘就是这里的高水位线了。
SQL> select * from t1;
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 86310 | 8512K| 344 (1)| 00:00:05 |
| 1 | TABLE ACCESS FULL| T1 | 86310 | 8512K| 344 (1)| 00:00:05 |
--------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
1237 consistent gets
0 physical reads
0 redo size
1343 bytes sent via SQL*Net to client
513 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
修正ORACLE表的高水位线
在ORACLE中,执行对表的删除操作不会降低该表的高水位线。而全表扫描将始终读取一个段(extent)中所有低于高水位线标记的块。如果在执行删除操作后不降低高水位线标记,则将导致查询语句的性能低下。下面的方法都可以降低高水位线标记。
1.执行表重建指令 alter table table_name move;
(在线转移表空间ALTER TABLE 。。。 MOVE TABLESPACE 。。。ALTER TABLE 。。。 MOVE 后面不跟参数也行,不跟参数表还是在原来的表空间,move后记住重建索引。如果以后还要继续向这个表增加数据,没有必要move,只是释放出来的空间,只能这个表用,其他的表或者segment无法使用该空间)
2.执行alter table table_name shrink space; 注意,此命令为Oracle 10g新增功能,再执行该指令之前必须允许行移动alter table table_name enable row movement;
3.emp/imp
4.alter table table_name deallocate unused
5.尽量truncate吧