上一次在说到数据库体系架构时已经提及数据库逻辑架构,逻辑架构主要包含:tablespace->segment->extent->block->os-block以及datafile,也说明了其中数据文件的部分管理方式,这里接着从这里开始说起比较好:
1、系统提供每一个表空间说明
2、大文件表空间
3、表空间文件主从关系
4、EXTENTS与SEGMENTS
5、高水位线介绍
6、DELETE、TRUNCATE、DROP、SHRINK SPACE区别
7、BLOCK存储原理
付:本来应该将SEGMENT一起说明的,不过SEGMENT是说明起来最复杂,也是体系架构中最终的关键部分,所以SEGMENT以后单独写一篇文章说明;而本文中最复杂的部分在“块”的说明中。
1、系统提供每一个表空间说明
首先查看有哪些表空间:
SQL> select tablespace_name,CONTENTS
2 from dba_tablespaces;
TABLESPACE_NAME CONTENTS
------------------------------ ---------
SYSTEM PERMANENT
UNDOTBS1 UNDO
SYSAUX PERMANENT
TEMP TEMPORARY
USERS PERMANENT
EXAMPLE PERMANENT
其中:
PERMANENT:表示永久表空间
UNDO:回退表空间
TEMPORARY:表示为临时表空间。
SYSTEM:是整个数据库最重要的表空间,存储的是数据字典,表的定义、视图定义、存储过程定义、用户信息、索引信息等都放于系统表空间中,系统表空间必须在线,其余都依赖于这个表空间存在,付:这个表空间不允许改名字。
SYSAUX:10g后新特性,系统辅助表空间(ORACLE 7i的系统表空间只有不到70M,8i不到200M,9i达到400M以上),后来将一些最核心的要保留较小,将最核心的留在SYSTEM表空间,其余的放置于SYSAUX表空间,付:系统内部这个表空间不允许改名字。
其余表空间都可以改名字,就这两个表空间不允许改名字。
SQL> select table_name from dict where table_name like '%AUX%';
TABLE_NAME
------------------------------
GV$SYSAUX_OCCUPANTS
V$SYSAUX_OCCUPANTS
SQL> desc V$SYSAUX_OCCUPANTS
名称
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
OCCUPANT_NAME
OCCUPANT_DESC
SCHEMA_NAME
MOVE_PROCEDURE
MOVE_PROCEDURE_DESC
SPACE_USAGE_KBYTES
SQL> COL OCCUPANT_NAME for a35
SQL> col OCCUPANT_DESC for a60
SQL> col SCHEMA_NAME for a30
SQL> col MOVE_PROCEDURE for a50
SQL> col SPACE_USAGE_KBYTES for 9999999999999999
SQL> set lines 260
SQL> select OCCUPANT_NAME,OCCUPANT_DESC,MOVE_PROCEDURE,SPACE_USAGE_KBYTES
2 FROM V$SYSAUX_OCCUPANTS;
OCCUPANT_NAME OCCUPANT_DESC MOVE_PROCEDURE SPACE_USAGE_KBYTES
----------------------------------- ------------------------------------------------------------ -------------------------------------------------- ------------------
LOGMNR LogMiner SYS.DBMS_LOGMNR_D.SET_TABLESPACE 6080
LOGSTDBY Logical Standby SYS.DBMS_LOGSTDBY.SET_TABLESPACE 896
STREAMS Oracle Streams 512
XDB XDB XDB.DBMS_XDB.MOVEXDB_TABLESPACE 49600
AO Analytical Workspace Object Table DBMS_AW.MOVE_AWMETA 21248
XSOQHIST OLAP API History Tables DBMS_XSOQ.OlapiMoveProc 21248
XSAMD OLAP Catalog DBMS_AMD.Move_OLAP_Catalog 15936
SM/AWR Server Manageability - Automatic Workload Repository 19520
SM/ADVISOR Server Manageability - Advisor Framework 4928
SM/OPTSTAT Server Manageability - Optimizer Statistics History 3968
SM/OTHER Server Manageability - Other Components 4992
OCCUPANT_NAME OCCUPANT_DESC MOVE_PROCEDURE SPACE_USAGE_KBYTES
----------------------------------- ------------------------------------------------------------ -------------------------------------------------- ------------------
STATSPACK Statspack Repository 0
ODM Oracle Data Mining MOVE_ODM 256
SDO Oracle Spatial MDSYS.MOVE_SDO 41536
WM Workspace Manager DBMS_WM.move_proc 7040
ORDIM Oracle interMedia ORDSYS Components 512
ORDIM/PLUGINS Oracle interMedia ORDPLUGINS Components 0
ORDIM/SQLMM Oracle interMedia SI_INFORMTN_SCHEMA Components 0
EM Enterprise Manager Repository emd_maintenance.move_em_tblspc 50880
TEXT Oracle Text DRI_MOVE_CTXSYS 4736
ULTRASEARCH Oracle Ultra Search MOVE_WK 0
ULTRASEARCH_DEMO_USER Oracle Ultra Search Demo User MOVE_WK 0
OCCUPANT_NAME OCCUPANT_DESC MOVE_PROCEDURE SPACE_USAGE_KBYTES
----------------------------------- ------------------------------------------------------------ -------------------------------------------------- ------------------
EXPRESSION_FILTER Expression Filter System 3712
EM_MONITORING_USER Enterprise Manager Monitoring User 1600
TSM Oracle Transparent Session Migration User 256
JOB_SCHEDULER Unified Job Scheduler 384
可以发现这些应用都是应用级别的,并非绝对的,所以放置于系统辅助表空间中,字段说明:
OCCUPANT_NAME:应用的名字
OCCUPANT_DESC:应用的描述信息
MOVE_PROCEDURE:要将其移动到另一个地方,需要使用哪一个过程。
USER表空间:本来是很普通的表空间,在10g后有一个新特性:
SQL> COL PROPERTY_NAME FOR A60
SQL> COL PROPERTY_VALUE FOR A35
SQL> COL DESCRIPTION FOR A60
SQL> l
1* SELECT * FROM DATABASE_PROPERTIES
SQL> /
PROPERTY_NAME PROPERTY_VALUE DESCRIPTION
------------------------------------------------------------ ----------------------------------- ------------------------------------
DICT.BASE 2 dictionary base tables version #
DEFAULT_TEMP_TABLESPACE TEMP Name of default temporary tablespace
DEFAULT_PERMANENT_TABLESPACE USERS Name of default permanent tablespace
DEFAULT_TBS_TYPE SMALLFILE Default tablespace type
NLS_LANGUAGE AMERICAN Language
NLS_TERRITORY AMERICA Territory
NLS_CURRENCY $ Local currency
NLS_ISO_CURRENCY AMERICA ISO currency
NLS_NUMERIC_CHARACTERS ., Numeric characters
NLS_CHARACTERSET ZHS16GBK Character set
NLS_CALENDAR GREGORIAN Calendar system
PROPERTY_NAME PROPERTY_VALUE DESCRIPTION
------------------------------------------------------------ ----------------------------------- ------------------------------------
NLS_DATE_FORMAT DD-MON-RR Date format
NLS_DATE_LANGUAGE AMERICAN Date language
NLS_SORT BINARY Linguistic definition
NLS_TIME_FORMAT HH.MI.SSXFF AM Time format
NLS_TIMESTAMP_FORMAT DD-MON-RR HH.MI.SSXFF AM Time stamp format
NLS_TIME_TZ_FORMAT HH.MI.SSXFF AM TZR Time with timezone format
NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR Timestamp with timezone format
NLS_DUAL_CURRENCY $ Dual currency symbol
NLS_COMP BINARY NLS comparison
NLS_LENGTH_SEMANTICS BYTE NLS length semantics
NLS_NCHAR_CONV_EXCP FALSE NLS conversion exception
PROPERTY_NAME PROPERTY_VALUE DESCRIPTION
------------------------------------------------------------ ----------------------------------- ------------------------------------
NLS_NCHAR_CHARACTERSET AL16UTF16 NCHAR Character set
NLS_RDBMS_VERSION 10.2.0.1.0 RDBMS version for NLS parameters
GLOBAL_DB_NAME ORCL103.REGRESS.RDBMS.DEV.US.ORACLE Global database name
.COM
EXPORT_VIEWS_VERSION 8 Export views revision #
DBTIMEZONE 00:00 DB time zone
SQL> alter database default tablespace SYSTEM;
数据库已更改。
SQL> SELECT * FROM DATABASE_PROPERTIES;
PROPERTY_NAME PROPERTY_VALUE DESCRIPTION
------------------------------------------------------------ ----------------------------------- -------------------------------------
DICT.BASE 2 dictionary base tables version #
DEFAULT_TEMP_TABLESPACE TEMP Name of default temporary tablespace
DEFAULT_PERMANENT_TABLESPACE SYSTEM Name of default permanent tablespace
DEFAULT_TBS_TYPE SMALLFILE Default tablespace type
NLS_LANGUAGE AMERICAN Language
NLS_TERRITORY AMERICA Territory
NLS_CURRENCY $ Local currency
NLS_ISO_CURRENCY AMERICA ISO currency
NLS_NUMERIC_CHARACTERS ., Numeric characters
NLS_CHARACTERSET ZHS16GBK Character set
NLS_CALENDAR GREGORIAN Calendar system
PROPERTY_NAME PROPERTY_VALUE DESCRIPTION
------------------------------------------------------------ ----------------------------------- -------------------------------------
NLS_DATE_FORMAT DD-MON-RR Date format
NLS_DATE_LANGUAGE AMERICAN Date language
NLS_SORT BINARY Linguistic definition
NLS_TIME_FORMAT HH.MI.SSXFF AM Time format
NLS_TIMESTAMP_FORMAT DD-MON-RR HH.MI.SSXFF AM Time stamp format
NLS_TIME_TZ_FORMAT HH.MI.SSXFF AM TZR Time with timezone format
NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR Timestamp with timezone format
NLS_DUAL_CURRENCY $ Dual currency symbol
NLS_COMP BINARY NLS comparison
NLS_LENGTH_SEMANTICS BYTE NLS length semantics
NLS_NCHAR_CONV_EXCP FALSE NLS conversion exception
PROPERTY_NAME PROPERTY_VALUE DESCRIPTION
------------------------------------------------------------ ----------------------------------- -------------------------------------
NLS_NCHAR_CHARACTERSET AL16UTF16 NCHAR Character set
NLS_RDBMS_VERSION 10.2.0.1.0 RDBMS version for NLS parameters
GLOBAL_DB_NAME ORCL103.REGRESS.RDBMS.DEV.US.ORACLE Global database name
.COM
EXPORT_VIEWS_VERSION 8 Export views revision #
DBTIMEZONE 00:00 DB time zone
默认表空间分系统级别和用户级别,DATABASE级别的创建后,如果创建用户不使用DEFALUT TABLESPACE指定,那么它就用DATABASE指定的DEFAULT TABLEPSACE了
2、大文件表空间
SQL> SELECT TABLESPACE_NAME,BIGFILE FROM DBA_TABLESPACES;
TABLESPACE_NAME BIG
------------------------------ ---
SYSTEM NO
UNDOTBS1 NO
SYSAUX NO
TEMP NO
USERS NO
EXAMPLE NO
大文件表空间的特性:
1、文件头大,从普通的8个块,可以到16个块。
2、长大到4G个块,每个块为8K,即每个数据文件可以达到32T大小,也就是一个表空间的最大的大小。
3、一个表空间至于一个数据文件,即表空间的最大大小不会变化。
为什么:ROWID决定,所谓大文件就是将文件编号的的区域划分给块编号了,所以一个数据文件可以存放更大的空间。
SQL> create bigfile tablespace tt2 datafile 'D:/ORACLE/ORADATA/ORCL103/DATAFILE/TT2.DBF' size 1m;
表空间已创建。
SQL> select * from dba_free_space;
TABLESPACE_NAME FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
------------------------------ ---------- ---------- ---------- ---------- ------------
SYSTEM 1 61161 262144 32 1
SYSTEM 1 61961 6225920 760 1
UNDOTBS1 2 185 65536 8 2
UNDOTBS1 2 201 131072 16 2
UNDOTBS1 2 241 262144 32 2
UNDOTBS1 2 281 65536 8 2
UNDOTBS1 2 313 196608 24 2
UNDOTBS1 2 353 65536 8 2
UNDOTBS1 2 385 65536 8 2
UNDOTBS1 2 401 65536 8 2
UNDOTBS1 2 441 262144 32 2
TABLESPACE_NAME FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
------------------------------ ---------- ---------- ---------- ---------- ------------
UNDOTBS1 2 513 131072 16 2
UNDOTBS1 2 553 131072 16 2
UNDOTBS1 2 577 131072 16 2
UNDOTBS1 2 601 589824 72 2
UNDOTBS1 2 681 262144 32 2
UNDOTBS1 2 721 131072 16 2
UNDOTBS1 2 745 131072 16 2
UNDOTBS1 2 769 524288 64 2
UNDOTBS1 2 841 262144 32 2
UNDOTBS1 2 881 196608 24 2
UNDOTBS1 2 913 65536 8 2
TABLESPACE_NAME FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
------------------------------ ---------- ---------- ---------- ---------- ------------
UNDOTBS1 2 929 262144 32 2
UNDOTBS1 2 969 1769472 216 2
UNDOTBS1 2 1209 131072 16 2
UNDOTBS1 2 1233 393216 48 2
UNDOTBS1 2 3201 65536 8 2
UNDOTBS1 2 3721 851968 104 2
UNDOTBS1 2 3833 393216 48 2
UNDOTBS1 2 3889 458752 56 2
UNDOTBS1 2 3953 131072 16 2
UNDOTBS1 2 3977 1048576 128 2
UNDOTBS1 2 4233 1048576 128 2
TABLESPACE_NAME FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
------------------------------ ---------- ---------- ---------- ---------- ------------
UNDOTBS1 2 4369 131072 16 2
UNDOTBS1 2 4393 65536 8 2
UNDOTBS1 2 4409 589824 72 2
SYSAUX 3 30945 8650752 1056 3
USERS 4 537 917504 112 4
USERS 4 1289 131072 16 4
USERS 4 2057 11534336 1408 4
USERS 4 3481 327680 40 4
EXAMPLE 5 465 2162688 264 5
EXAMPLE 5 1313 458752 56 5
EXAMPLE 5 10265 20774912 2536 5
TABLESPACE_NAME FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
------------------------------ ---------- ---------- ---------- ---------- ------------
TT2 6 17 917504 112 1024
现在BLOCK_ID从第17个块开始,可使用块只有112个块。
SQL> alter database datafile 'D:/ORACLE/ORADATA/ORCL103/DATAFILE/TT2.DBF' autoextend on;
数据库已更改。
SQL> c/max_blocks/maxblocks
1* SELECT file_name,maxblocks from dba_data_files
SQL> /
FILE_NAME MAXBLOCKS
------------------------------------------------------------ ----------
D:/ORACLE/ORADATA/ORCL103/DATAFILE/O1_MF_USERS_63S35M2X_.DBF 4194302
D:/ORACLE/ORADATA/ORCL103/DATAFILE/O1_MF_SYSAUX_63S35LWS_.DB 4194302
F
D:/ORACLE/ORADATA/ORCL103/DATAFILE/O1_MF_UNDOTBS1_63S35M1Y_. 4194302
DBF
D:/ORACLE/ORADATA/ORCL103/DATAFILE/O1_MF_SYSTEM_63S35LVC_.DB 4194302
F
D:/ORACLE/ORADATA/ORCL103/DATAFILE/O1_MF_EXAMPLE_63S37HQX_.D 4194302
FILE_NAME MAXBLOCKS
------------------------------------------------------------ ----------
BF
D:/ORACLE/ORADATA/ORCL103/DATAFILE/TT2.DBF 4294967293
比普通的数据文件最大值大1024倍。
SQL> alter tablespace tt2 add datafile 'D:/ORACLE/ORADATA/ORCL103/DATAFILE/TT2.DBF' size 2m;
alter tablespace tt2 add datafile 'D:/ORACLE/ORADATA/ORCL103/DATAFILE/TT2.DBF' size 2m
*
第 1 行出现错误:
ORA-32771: 无法在大文件表空间中添加文件
大文件使用海量连续存储数据,对控制文件有好处,以前控制文件存储上百个数据文件信息,此时值存储一个即可。
SQL> ALTER TABLESPACE TBS_TEST DROP DATAFILE 'D:/ORACLE/ORADATA/ORCL102/TBS_TEST03.DBF';
表空间已更改。
SQL> ALTER TABLESPACE TBS_TEST DROP DATAFILE 'D:/ORACLE/ORADATA/ORCL102/TBS_TEST02.DBF';
表空间已更改。
SQL> drop tablespace TBS_TEST;
3、表空间文件主从关系
SQL> SELECT FILE_NAME,TABLESPACE_NAME FROM DBA_DATA_FILES
2 WHERE TABLESPACE_NAME='TBS_TEST';
FILE_NAME TABLESPACE_NAME
-------------------------------------------------- ------------------------------------------------
D:/ORACLE/ORADATA/ORCL102/TBS_TEST01.DBF TBS_TEST
D:/ORACLE/ORADATA/ORCL102/TBS_TEST02.DBF TBS_TEST
SQL> ALTER TABLESPACE TBS_TEST ADD DATAFILE 'D:/ORACLE/ORADATA/ORCL102/TBS_TEST03.DBF' size 1m;
表空间已更改。
SQL> SELECT FILE_NAME,TABLESPACE_NAME FROM DBA_DATA_FILES
2 WHERE TABLESPACE_NAME='TBS_TEST';
FILE_NAME TABLESPACE_NAME
-------------------------------------------------- ---------------------------------------------
D:/ORACLE/ORADATA/ORCL102/TBS_TEST01.DBF TBS_TEST
D:/ORACLE/ORADATA/ORCL102/TBS_TEST02.DBF TBS_TEST
D:/ORACLE/ORADATA/ORCL102/TBS_TEST03.DBF TBS_TEST
SQL> ALTER TABLESPACE TBS_TEST DROP DATAFILE 'D:/ORACLE/ORADATA/ORCL102/TBS_TEST01.DBF';
ALTER TABLESPACE TBS_TEST DROP DATAFILE 'D:/ORACLE/ORADATA/ORCL102/TBS_TEST01.DBF'
*
第 1 行出现错误:
ORA-03263: 无法删除表空间 TBS_TEST 的第一个文件
表空间已删除。
4、EXTENTS与SEGMENTS
SQL> select tablespace_name,segment_name,extents,blocks,segment_type
2 FROM dba_segments
3 WHERE OWNER='SCOTT';
TABLESPACE_NAME SEGMENT_NAME EXTENTS BLOCKS SEGMENT_TYPE
------------------------------ --------------------------------------------------------------------------------- ---------- ---------- -----
USERS PK_DEPT 1 8 INDEX
USERS DEPT 1 8 TABLE
USERS EMP 1 8 TABLE
USERS PK_EMP 1 8 INDEX
USERS BONUS 1 8 TABLE
USERS SALGRADE 1 8 TABLE
USERS TT 1 8 TABLE
USERS AAA 1 8 TABLE
USERS TABLE_01 1 8 TABLE
USERS TABLE_02 1 8 TABLE
USERS PERSON 1 8 TABLE
TABLESPACE_NAME SEGMENT_NAME EXTENTS BLOCKS SEGMENT_TYPE
------------------------------ --------------------------------------------------------------------------------- ---------- ---------- -----
USERS V_USER_OBJECTS 21 768 TABLE
USERS V_DBA_OBJECTS 21 768 TABLE
USERS TEST_OBJECTS 2 16 TABLE
USERS TEST 1 8 TABLE
ORA10TEST EMP_OTHER 1 8 TABLE
USERS TABLE_AJ_TEST 1 8 TABLE
已选择17行。
SQL> grant select any dictionary to scott;
授权成功。
SQL> CREATE TABLE AAA(COL1 NUMBER,COL2 VARCHAR2(20));
表已创建。
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='AAA';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 6 1049 8
也就是说一个表只要以创建就有8个BLOCKS,这8个块为表头。
分配EXTENT(范围)的三种方式:
1、创建表和索引的时候要分配EXTENTS初步的范围
2、数据量增长的时候分配额外的范围
3、手工分配范围。
先插入一些数据:
SQL> INSERT INTO AAA SELECT 1,1 FROM EMP;
已创建14行。
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='AAA';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 6 1049 8
发现BLOCKS没有变化,看来前8个BLOCK并不完全是头部,下面继续证明。
然后重复执行N次复制数据:
INSERT INTO AAA SELECT * FROM AAA;
当数据中途发生:
SQL> SELECT COUNT(1) FROM AAA;
COUNT(1)
----------
3584
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='AAA';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 6 1049 8
1 4 57 8
此时跨越了数据文件,也有新的BLOCK_ID开始的8个块。说明EXTENT相互之间可以不连续存储,而EXTENT内部是连续分配的多个块。
继续增加N多次以后数据:
SQL> SELECT COUNT(1) FROM AAA;
COUNT(1)
----------
114688
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='AAA';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 6 1049 8
1 4 57 8
2 6 1057 8
3 6 1065 8
4 6 1073 8
5 6 1081 8
6 6 1089 8
7 6 1097 8
8 6 1105 8
9 6 1113 8
10 6 1121 8
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
11 6 1129 8
12 6 1137 8
13 6 1145 8
14 6 1153 8
15 6 1161 8
16 6 1289 128
出现128块了?这么奇怪的事情,为什么变大了呢?其实当你继续插入的时候,到第72个EXTENT的时候会变成1024个块(8M),然后再到8192个块(64M)等等,这是一个规律,当ORACLE发现数据量很大的时候,分配的范围就会越来越大,因为这样方便插入,预留空间,至于细节由ORACLE自己决定。
而SEGMENT是一个更大的概念,它包含一系列相同类型并属于同一逻辑对象的EXTENT的组合,当你创建一个表或者一个索引或者一个分区的新的分区的时候都会产生一个新的SEGMENT,也就是他是逻辑对象的标志,逻辑对象上有一个OBJECT_ID和DATA_OBJECT_ID的概念,在说到TRUNCATE的时候会提及。
--当有大量输出插入时,此时可以预先分配,然后就可以预先分配空间方便插入。
分区表对某一个分区手工分配EXTENTS:
分布区表为:alter table <table_name> modify partition <partition_name> allocate extent(size 20m);
SQL> alter table AAA allocate extent(size 10m);
表已更改。
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='AAA';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 6 1049 8
1 4 57 8
2 6 1057 8
3 6 1065 8
4 6 1073 8
5 6 1081 8
6 6 1089 8
7 6 1097 8
8 6 1105 8
9 6 1113 8
10 6 1121 8
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
11 6 1129 8
12 6 1137 8
13 6 1145 8
14 6 1153 8
15 6 1161 8
16 6 1289 128
17 6 1417 128
18 6 1545 128
19 6 1673 128
20 6 1801 128
21 6 1929 128
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
22 6 2057 128
23 6 2185 128
24 6 2313 128
25 6 2441 128
26 6 2569 128
27 6 2697 128
28 6 2825 128
回收EXTENT:
SQL> alter table aaa deallocate unused;
表已更改。
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='AAA';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 6 1049 8
1 4 57 8
2 6 1057 8
3 6 1065 8
4 6 1073 8
5 6 1081 8
6 6 1089 8
7 6 1097 8
8 6 1105 8
9 6 1113 8
10 6 1121 8
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
11 6 1129 8
12 6 1137 8
13 6 1145 8
14 6 1153 8
15 6 1161 8
16 6 1289 128
17 6 1417 128
18 6 1545 128
19 6 1673 128
20 6 1801 128
SQL> DELETE FROM aaa;
分区表对某个分区的EXTENTS回收时:
alter table <table_name> modify partition <partition_name> deallocate unused keep 10m;
alter table <table_name> modify partition <partition_name> deallocate unused;
--前者为保存最小范围,即即使有更多的空间可以回收,但是要保证最小有10M的EXTENT存在
--后者为回收掉所有没有使用的EXTENT。
SQL> alter table aaa deallocate unused;
表已更改。
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='AAA';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 6 1049 8
1 4 57 8
2 6 1057 8
3 6 1065 8
4 6 1073 8
5 6 1081 8
6 6 1089 8
7 6 1097 8
8 6 1105 8
9 6 1113 8
10 6 1121 8
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
11 6 1129 8
12 6 1137 8
13 6 1145 8
14 6 1153 8
15 6 1161 8
16 6 1289 128
17 6 1417 128
18 6 1545 128
19 6 1673 128
20 6 1801 128
发现用DELETE删除掉的数据,无法将EXTENT回收,因为deallocate是回收高水位线以上的内容,而不是回收高水位线一下的空块,下面会提及什么是高水位线,TRUNCATE、DROP、SHRINK SPACE的区别所在。
这里用SHRINK SPACE做一个操作,其余的TRUNCATE和DROP就不用多说了:
SQL> alter table aaa enable row movement;
表已更改。
SQL> alter table aaa shrink space;
表已更改。
SQL> alter table aaa disable row movement;
表已更改。
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='AAA';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 6 1049 8
通过SHRINK SPACE后,变成了8个块了。
5、高水位线介绍
1、全表扫描的终点 从第一个块到这个块
2、并行插入的起点大量加载数据,海量数据加载,直接用新块来装,而不是去找空块。/*+append*/
高水位线插入的逻辑图形如下(为什么叫逻辑图形,是因为实际的情况下有还要分块是自动管理的还是人工管理的,在ORACLE 10G的第二个版本自己创建的表空间默认是自动管理的,在块部分会专门介绍):
说明:deallocate是回收高水位线以上的进行回收掉,从上一个试验已经可以查看到了,不过为了专门说明这个,来做一个新的实验:
SQL> create table t1 as select * from emp where 1=2;
表已创建。
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='T1';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 6 1057 8
SQL> INSERT INTO t1 select * from emp;
已创建14行。
SQL> INSERT INTO t1 select * from t1;
已创建14行。
SQL> /
已创建28行。
SQL> /
已创建56行。
SQL> /
已创建112行。
SQL> /
已创建224行。
SQL> /
已创建448行。
SQL> /
已创建896行。
SQL> /
已创建1792行。
SQL> commit;
提交完成。
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='T1';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 6 1057 8
1 4 57 8
2 6 1065 8
3 4 633 8
SQL> DELETE FROM T1;
已删除3584行。
SQL> commit;
提交完成。
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='T1';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 6 1057 8
1 4 57 8
2 6 1065 8
3 4 633 8
SQL> alter table t1 deallocate unused;
表已更改。
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='T1';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 6 1057 8
1 4 57 8
2 6 1065 8
3 4 633 8
要回收这部分空间该如何操作呢?压缩,将表的空块进行压缩:
SQL> alter table t1 enable row movement;
表已更改。
SQL> alter table t1 shrink space;
表已更改。
SQL> alter table t1 disable row movement;
表已更改。
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='T1';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 6 1057 8
这使得我们对DELETE、TRUNCATE、DROP、SHRINK SPACE几个参数到底做了什么有很大的兴趣,至于deallocate已经知道是回收高水位线以上的信息,那么这几个呢下面接着说:
6、DELETE、TRUNCATE、DROP、SHRINK SPACE区别
其实这部分已经在前面有所引导,这里再总结一下,然后做个简单试验:
DELETE:
1、只是对数据库块删除,相当于打一个标记一样,不会回收表空间,但是如果指针指向这个块的时候,这部分空间是可以被使用的;
2、数据会在UNDO表空间中存储一段时间(这部分会在专门讲解SEGMENT的时候说明);
3、使用手工提交,一些常规退出时会自动提交。
4、在非归档模式下可以在一定程度上进行程度的回退,在归档模式下几可以完全回退。
5、可以进行闪回
6、因为不会回收表空间,也不就不会回收高水位。
7、会产生大量的日志信息(即要保存以前的,也要保存现在的,所以UPDATE语句是最慢的)。
TRUNCATE(默认自带 DROP STORAGE参数,即删除存储):
1、产生非常少的日志信息、UNDO信息
2、认为是DDL语句,所以执行完就没有COMMIT的动作,直接提交
3、不能回退与闪回。
4、回收掉高水位信息,并释放空间。
5、保留大小为TABLE初始化创建时的STORAGE(initial 128k)的大小,默认情况下这个是8个块的大小,即64k。
6、由于其数据块的EXNTENT只剩下初始化的保留块,所以对象的DATA_OBJECT_ID将会被改变,OBJECT_ID是不会变化的,因为保留块部分没有被改变;付:如果这个表没有任何一行数据,直接TRUNCATE,DATA_OBJECT_ID也是不会变化的。
DROP:
1、不带PURGE的DROP只是修改名字,相当于一个RENAME操作,修改系统表空间SYSTEM的相应数据字典而已。
2、不带PURGE操作的DROP操作,表空间不会被释放,这个能保存多久不好说,一般来说只要表空间够用,就一直可以通过FLASHBACK闪回,当表空间不够用的时候,这部分空间将会被其他的空间所占用了,而且一次性将整个一个表的空间全部释放。
2、带PURGE操作的DROP操作,是彻底清楚数据并释放表空间信息。
SHRINK SPACE:
1、前提是允许表进行迁移,即,ROW MOVEMENT是ENABLE的。
2、将数据进行集中处理。
3、将空块进行回收。
4、即使是表定义中的initial的大小,也可以被回收掉。
测试实验如下:
SQL> drop table t1 purge;
表已删除。
SQL> create table t1 storage(initial 20m) as select * from emp where 1=2;
表已创建。
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='T1';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 6 1161 128
1 6 1289 128
2 6 1417 128
3 6 1545 128
4 6 1673 128
5 6 1801 128
6 6 1929 128
7 6 2057 128
8 6 2185 128
9 6 2313 128
10 6 2441 128
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
11 6 2569 128
12 6 2697 128
13 6 2825 128
14 6 2953 128
15 6 3081 128
16 6 3209 128
17 6 3337 128
18 6 3465 128
19 6 3593 128
已选择20行。
SQL> truncate table t1;
表被截断。
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='T1';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 6 1161 128
1 6 1289 128
2 6 1417 128
3 6 1545 128
4 6 1673 128
5 6 1801 128
6 6 1929 128
7 6 2057 128
8 6 2185 128
9 6 2313 128
10 6 2441 128
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
11 6 2569 128
12 6 2697 128
13 6 2825 128
14 6 2953 128
15 6 3081 128
16 6 3209 128
17 6 3337 128
18 6 3465 128
19 6 3593 128
已选择20行。
SQL> alter table t1 enable row movement;
表已更改。
SQL> alter table t1 shrink space;
表已更改。
SQL> alter table t1 disable row movement;
表已更改。
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='T1';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 6 1161 8
7、BLOCK存储原理
说到块,首先要提及一个问题,就是TABLESPACE的对SEGMENT_SPACE的管理方式有两种,分别是:MANUAL(人工)、AUTO(自动),在ORACLE 10G的第二个版本开始,自己创建的表空间默认是采用AUTO自动方式,下面分两大板块来说明什么是MANUAL,什么AUTO方式。
首先定义BLOCK的存储方式:
然后开始看下MANUAL与AUTO:
SQL> SELECT TABLESPACE_NAME,SEGMENT_SPACE_MANAGEMENT FROM DBA_TABLESPACES;
TABLESPACE_NAME SEGMEN
------------------------------ ------
SYSTEM MANUAL
UNDOTBS1 MANUAL
SYSAUX AUTO
TEMP MANUAL
USERS AUTO
TABLESPACE_NAME SEGMEN
------------------------------ ------
ORA10TEST AUTO
可以发现,自己创建的表空间都是AUTO的方式,而默认的几个表空间都是MANUAL,这个是在创建表空间的时候决定,我们来看下SYSTEM表空间的创建语句:
SQL> set long 10000
SQL> set pages 20
SQL> set lines 200
SQL> select dbms_metadata.get_ddl('TABLESPACE','SYSTEM') FROM DUAL;
DBMS_METADATA.GET_DDL('TABLESPACE','SYSTEM')
----------------------------------------------------------------------
CREATE TABLESPACE "SYSTEM" DATAFILE
'D:/ORACLE/ORADATA/ORCL102/SYSTEM01.DBF' SIZE 314572800
AUTOEXTEND ON NEXT 10485760 MAXSIZE 32767M,
'D:/ORACLE/ORADATA/ORCL102/SYSTEM02.DBF' SIZE 1073741824,
'D:/ORACLE/ORADATA/ORCL102/SYSTEM03.DBF' SIZE 104857600
LOGGING ONLINE PERMANENT BLOCKSIZE 8192
EXTENT MANAGEMENT LOCAL AUTOALLOCATE SEGMENT SPACE MANAGEMENT MANUAL
ALTER DATABASE DATAFILE
'D:/ORACLE/ORADATA/ORCL102/SYSTEM01.DBF' RESIZE 503316480
ALTER DATABASE DATAFILE
'D:/ORACLE/ORADATA/ORCL102/SYSTEM03.DBF' RESIZE 134217728
再看下USER表空间的定义:
SQL> SELECT DBMS_METADATA.GET_DDL('TABLESPACE','USERS') FROM dual;
DBMS_METADATA.GET_DDL('TABLESPACE','USERS')
-----------------------------------------------------------------------
CREATE TABLESPACE "USERS" DATAFILE
'D:/ORACLE/ORADATA/ORCL102/USERS01.DBF' SIZE 5242880
AUTOEXTEND ON NEXT 1310720 MAXSIZE 32767M,
'D:/ORACLE/ORADATA/ORCL102/USERS02.DBF' SIZE 268435456
LOGGING ONLINE PERMANENT BLOCKSIZE 8192
EXTENT MANAGEMENT LOCAL AUTOALLOCATE SEGMENT SPACE MANAGEMENT AUTO
此时自己创建一个MANUAL的表空间来做测试:
SQL> create tablespace tbs_manual datafile 'D:/ORACLE/ORADATA/ORCL102/manual01.dd' size 10m SEGMENT SPACE MANAGEMENT MANUAL;
表空间已创建。
SQL> create table tt tablespace tbs_manual as select * from emp where 1=2;
表已创建。
SQL> select tablespace_name from tabs where table_name='TT';
TABLESPACE_NAME
------------------------------
TBS_MANUAL
SQL> SELECT extent_ID,FILE_ID,BLOCK_ID,BLOCKS
2 FROM dba_extents
3 WHERE owner='SCOTT'
4 AND SEGMENT_NAME='TT';
EXTENT_ID FILE_ID BLOCK_ID BLOCKS
---------- ---------- ---------- ----------
0 20 9 8
说明这个表的第一个块的编号是9,那么向后数八个块分别就是:
9 10 11 12 13 14 15 16 这8个块;那么我们看下数据块的头部是存放在那里的呢?
SQL> SELECT HEADER_BLOCK FROM DBA_SEGMENTS
2 WHERE OWNER='SCOTT' AND SEGMENT_NAME='TT';
HEADER_BLOCK
------------
9
SQL> analyze table tt compute statistics;
表已分析。
SQL> SELECT BLOCKS,EMPTY_BLOCKS,FREELISTS,NUM_FREELIST_BLOCKS,PCT_FREE,PCT_USED
2 FROM TABS WHERE TABLE_NAME='TT';
BLOCKS EMPTY_BLOCKS FREELISTS NUM_FREELIST_BLOCKS PCT_FREE PCT_USED
---------- ------------ ---------- ------------------- ---------- ----------
0 7 1 0 10 40
可以发现有7个空数据块(因为有一个头部块11号块),FREELIST只有一个,PCT_FREE为表定义时决定,即当数据块内部的数据空闲空间少于这个数据的时候,就不允许再继续存放数据了,这是一个百分比,这里指当空闲空间少于8K的10%的时候,就不允许继续想内部增加数据,这部分空间用于块内部的数据进行字段加长用,如果块内部的数据经常做UPDATE,这个值可以适当增大一点,如果这个数据几乎不会做UPDATE操作,如一些固定的配置表一般只会做INSERT操作,那么就将他改成0;PCT_USED是代表当数据块小于这个百分比的时候,该数据库可以继续插入数据,如果为自动管理的表空间这部分为空。
为了一窥他们的究竟,我们讲数据块导出来看看里面是存放什么东西,先来导出头部块:
先看下导出目录:
SQL> show parameter user_dump
NAME TYPE VALUE
------------------------------------ ----------- -----------------------------
user_dump_dest string D:/ORACLE/ADMIN/ORCL102/UDUMP
删除掉目录下所有东西(LINUX下用RM):
SQL> host del D:/ORACLE/ADMIN/ORCL102/UDUMP/*.*
D:/ORACLE/ADMIN/ORCL102/UDUMP/*.*, 是否确认(Y/N)? Y
查看一下数据文件在一个文件中:
SQL> select file_id,block_id from dba_extents where segment_name='TT';
FILE_ID BLOCK_ID
---------- ----------
20 9
我们导出第9块:
SQL> alter system dump datafile 20 block 9;
系统已更改。
此时发现刚才的目录(D:/ORACLE/ADMIN/ORCL102/UDUMP/)出现一个新的TRC文件,打开看下内容主要部分如下:
Dump file d:/oracle/admin/orcl102/udump/orcl102_ora_724.trc
Mon Aug 02 13:46:07 2010
ORACLE V10.2.0.1.0 - Production vsnsta=0
vsnsql=14 vsnxtr=3
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
Windows XP Version V5.1 Service Pack 2
CPU : 2 - type 586
Process Affinity : 0x00000000
Memory (Avail/Total): Ph:1810M/3036M, Ph+PgF:2149M/4921M, VA:847M/2047M
Instance name: orcl102
Redo thread mounted by this instance: 1
Oracle process number: 17
Windows thread id: 724, image: ORACLE.EXE (SHAD)
*** 2010-08-02 13:46:07.828
*** ACTION NAME:() 2010-08-02 13:46:07.812
*** MODULE NAME:(SQL*Plus) 2010-08-02 13:46:07.812
*** SERVICE NAME:(SYS$USERS) 2010-08-02 13:46:07.812
*** SESSION ID:(314.13) 2010-08-02 13:46:07.812
Start dump data blocks tsn: 18 file#: 20 minblk 9 maxblk 9
buffer tsn: 18 rdba: 0x05000009 (20/9)
scn: 0x0000.11cbd388 seq: 0x01 flg: 0x04 tail: 0xd3881001
frmt: 0x02 chkval: 0x113d type: 0x10=DATA SEGMENT HEADER - UNLIMITED
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x08732200 to 0x08734200
8732200 0000A210 05000009 11CBD388 04010000 [................]
8732210 0000113D 00000000 00000000 00000000 [=...............]
8732220 00000000 00000001 00000007 00001020 [............ ...]
8732230 00000000 00000000 00000007 0500000A [................]
8732240 00000000 00000000 00000000 00000000 [................]
8732250 00000000 00000000 00000000 00000001 [................]
8732260 00000000 0000E3C9 40000000 0500000A [...........@....]
8732270 00000007 00000000 00000000 00000000 [................]
8732280 00000000 00000000 00000000 00000000 [................]
Repeat 250 times
8733230 00000000 00010000 00010001 00000000 [................]
8733240 00000000 00000000 00000000 00000000 [................]
Repeat 250 times
87341F0 00000000 00000000 00000000 D3881001 [................]
Extent Control Header
-----------------------------------------------------------------
Extent Header:: spare1: 0 spare2: 0 #extents: 1 #blocks: 7
last map 0x00000000 #maps: 0 offset: 4128
Highwater:: 0x0500000a ext#: 0 blk#: 0 ext size: 7
#blocks in seg. hdr's freelists: 0
#blocks below: 0
mapblk 0x00000000 offset: 0
Unlocked
Map Header:: next 0x00000000 #extents: 1 obj#: 58313 flag: 0x40000000
Extent Map
-----------------------------------------------------------------
0x0500000a length: 7
nfl = 1, nfb = 1 typ = 1 nxf = 0 ccnt = 0
SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000
End dump data blocks tsn: 18 file#: 20 minblk 9 maxblk 9
其余部分暂时不用多看,前面是一些描述信息,中间是存放的些数据,人类几乎看不太懂,在说存放数据的时候再说,先看红色标注部分:
DATA SEGMENT HEADER:说明这是一个数据块头部。
0x0500000a:代表的是数据块的起始位置,BLOCK为9,那么数据块从10开始,而a正好是代表16进制的10。
length: 7 代表目前头部块管理的数据链表长度为7,和我们预想一致。
我们插入一条数据插入到哪里去了?我们用ROWID来找一找看下。
SQL> select rowid,dbms_rowid.rowid_block_number(rowid) file# from tt;
ROWID FILE#
------------------ ----------
AAAOPKAAUAAAAAKAAA 10
说明插入数据块10,是否是有顺序的呢?我们继续插入,用INSERT INTO TTSELECT * FROM TT自我复制,数据大概两百多行的时候再看:
SQL> select block#,count(1) from( select dbms_rowid.rowid_block_number(rowid) block# from tt) group by block#;
FILE# COUNT(1)
---------- ----------
11 171
13 79
10 171
12 171
此时发现数据块变成了4个,而且使用了10、11、12、13,说明其使用的确是顺序的,那么开始说的PCT_USED当数据块少了的时候会有变化吗?我们把11块的数据全部删掉,再往里面放一些数据,看怎么样的:
SQL> DELETE FROM TT WHERE DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid)=11;
已删除171行。
SQL> select file#,count(1) from( select dbms_rowid.rowid_block_number(rowid) file# from tt) group by file#;
FILE# COUNT(1)
---------- ----------
13 79
10 171
12 171
SQL> commit;
提交完成。
SQL> insert into tt select * from tt;
已创建421行。
SQL> commit;
提交完成。
SQL> select file#,count(1) from( select dbms_rowid.rowid_block_number(rowid) file# from tt) group by file#;
FILE# COUNT(1)
---------- ----------
11 171
13 171
14 158
10 171
12 171
SQL> analyze table tt compute statistics;
表已分析。
SQL> SELECT BLOCKS,EMPTY_BLOCKS,FREELISTS,NUM_FREELIST_BLOCKS,PCT_FREE,PCT_USED
2 FROM TABS WHERE TABLE_NAME='TT';
BLOCKS EMPTY_BLOCKS FREELISTS NUM_FREELIST_BLOCKS PCT_FREE PCT_USED
---------- ------------ ---------- ------------------- ---------- ----------
5 2 1 2 10 40
此时BLOCKS从0变成5个块,说明是被使用的块,EMPTY_BLOCK是2。
若某些表只会进行INSERT操作,没有UPDATE操作,PCT_FREE就可以设置为0,通过命令:
alter table tt pctfree 0;
即可修改,测试一下,开始一个块存放大概171行数据,是90%就跳过,那么预计修改是190条数据每个块就跳过:
SQL> select file#,count(1) from( select dbms_rowid.rowid_block_number(rowid) file# from tt) group by file# order by file#;
FILE# COUNT(1)
---------- ----------
10 171
11 190
12 171
13 171
14 190
15 190
16 190
17 69
和我们预计的几乎一致,第17块尚未装满,所以为69条数据,以前的块既往不咎,那再改成一半试一试看:
SQL> alter table tt pctfree
2 50;
表已更改。
SQL> insert into tt select * from tt;
已创建1342行。
SQL> commit;
提交完成。
SQL> select file#,count(1) from( select dbms_rowid.rowid_block_number(rowid) file# from tt) group by file# order by file#;
FILE# COUNT(1)
---------- ----------
10 171
11 190
12 171
13 171
14 190
15 190
16 190
17 94
18 95
19 94
20 94
21 94
22 95
23 94
24 95
25 94
26 95
FILE# COUNT(1)
---------- ----------
27 95
28 95
29 94
30 95
31 88
看来的确是我们想要的理想效果,在适当的情况下选择适当的大小,可以该节约空间就节约空间,该节约提高时间就节约时间。
SQL> SELECT BLOCKS,EMPTY_BLOCKS,FREELISTS,NUM_FREELIST_BLOCKS,PCT_FREE,PCT_USED
2 FROM TABS WHERE TABLE_NAME='TT';
BLOCKS EMPTY_BLOCKS FREELISTS NUM_FREELIST_BLOCKS PCT_FREE PCT_USED
---------- ------------ ---------- ------------------- ---------- ----------
23 0 1 2 50 40
付:MANUAL管理方式在9i以前以及10g出来的第一个版本都是这样管理的,他是将块与块之间用链表相连接,指针指向当前操作的数据块,那个块有空间就向哪里蹦,如果数据块来回DELETE、UPDATE操作,会使得这个指针来回蹦,造成很大的性能问题,所以在ORACLE 10G的第二个版本,默认自己创建的表空间,使用自动管理方式,下面来看下自动管理和它的区别:
SEGMENT SPACE AUTO表空间的BLOCK:
先将开始该清理的东西清理掉:
SQL> drop tablespace tbs_manual including contents;
表空间已删除。
SQL> host del D:/oracle/oradata/orcl102/MANUAL01.DD
SQL> create tablespace tbs_manual datafile 'D:/oracle/oradata/orcl102/MANUAL01.DD' size 10m;
表空间已创建。
SQL> create table tt tablespace tbs_manual as select * from emp where 1=2;
表已创建。
SQL> SELECT TABLE_NAME,PCT_USED,PCT_FREE FROM TABS;
TABLE_NAME PCT_USED PCT_FREE
------------------------------ ---------- ----------
DEPT 10
EMP 10
BONUS 10
SALGRADE 10
AAA 10
TT 10
TABLE_01 10
TABLE_02 10
PERSON 10
V_USER_OBJECTS 10
V_DBA_OBJECTS 10
TEST_OBJECTS 10
TEST 10
EMP_OTHER 10
TABLE_AJ_TEST 10
TEMPDBA 40 10
T1 10
发现部行的PCT_USED字段有值,部分没有值,这里没有值就是自动管理的,有值的是手动管理的。
看下范围信息:
SQL> SELECT BLOCK_ID,BLOCKS FROM DBA_EXTENTS
2 WHERE OWNER='SCOTT' AND SEGMENT_NAME='TT';
BLOCK_ID BLOCKS
---------- ----------
9 8
发现和手工管理的这部分没有区别,再看下头部在那里?
SQL> SELECT HEADER_BLOCK FROM DBA_SEGMENTS
2 WHERE SEGMENT_NAME='TT';
HEADER_BLOCK
------------
11
为什么头部不是第9个块了呢?而是第11个,是随机的嘛?不是,肯定的,这里说明一下,自动管理的表的头部块在每个表创建的第一个EXTENTS的第三个块,而第一个块是一级位图,管理第一个EXNTENT内部的所有块信息,第二个块是二级位图,管理表扩展后其他EXTENT的头部块的信息,其余EXTENT有两个头部,根据EXTENT所管理块的数量一个分一半,当第二个快管理不过来的时候向头部块借位管理,如果两个块还管不过来,此时加二级树结构来管理头部节点(这个范围已经足够满足我们的要求),最多三层。
我们将这三个快导出来看下是什么东西:
分别是编号为9、10、11块:
SQL> select file_id,BLOCK_ID,BLOCKS FROM DBA_EXTENTS
2 WHERE OWNER='SCOTT' AND SEGMENT_NAME='TT';
FILE_ID BLOCK_ID BLOCKS
---------- ---------- ----------
20 9 8
SQL> alter system dump datafile 20 block 9;
系统已更改。
第9块关键信息:
Start dump data blocks tsn: 18 file#: 20 minblk 9 maxblk 9
buffer tsn: 18 rdba: 0x05000009 (20/9)
scn: 0x0000.11cbe288 seq: 0x01 flg: 0x04 tail: 0xe2882001
frmt: 0x02 chkval: 0x643b type: 0x20=FIRST LEVEL BITMAP BLOCK
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x080B2200 to 0x080B4200
80B2200 0000A220 05000009 11CBE288 04010000 [ ...............]
80B2210 0000643B 00000000 00000000 00000000 [;d..............]
80B2220 00000000 00000000 00000000 00000000 [................]
Repeat 1 times
80B2240 00000000 00000000 00000000 00000004 [................]
80B2250 FFFFFFFF 00000005 00000003 00000008 [................]
80B2260 00010001 00000000 00000000 00000000 [................]
80B2270 00000000 00000003 00000000 00000000 [................]
80B2280 00000000 00000000 00000000 00000000 [................]
80B2290 0500000A 00000000 00000000 00000003 [................]
80B22A0 00000008 0500000C 00000000 00000000 [................]
80B22B0 00000000 00000000 00000000 00000001 [................]
80B22C0 0000E3CC 00000000 00000000 05000009 [................]
80B22D0 00000008 00000000 00000000 00000000 [................]
80B22E0 00000000 00000000 00000000 00000000 [................]
Repeat 9 times
80B2380 00000000 00000000 00000000 00001011 [................]
80B2390 00000000 00000000 00000000 00000000 [................]
Repeat 485 times
80B41F0 00000000 00000000 00000000 E2882001 [............. ..]
Dump of First Level Bitmap Block
--------------------------------
nbits : 4 nranges: 1 parent dba: 0x0500000a poffset: 0
unformatted: 5 total: 8 first useful block: 3
owning instance : 1
instance ownership changed at
Last successful Search
Freeness Status: nf1 0 nf2 0 nf3 0 nf4 0
Extent Map Block Offset: 4294967295
First free datablock : 3
Bitmap block lock opcode 0
Locker xid: : 0x0000.000.00000000
Inc #: 0 Objd: 58316
HWM Flag: HWM Set
Highwater:: 0x0500000c ext#: 0 blk#: 3 ext size: 8
#blocks in seg. hdr's freelists: 0
#blocks below: 0
mapblk 0x00000000 offset: 0
--------------------------------------------------------
DBA Ranges :
--------------------------------------------------------
0x05000009 Length: 8 Offset: 0
0:Metadata 1:Metadata 2:Metadata 3:unformatted
4:unformatted 5:unformatted 6:unformatted 7:unformatted
--------------------------------------------------------
End dump data blocks tsn: 18 file#: 20 minblk 9 maxblk 9
FIRST LEVEL BITMAP BLOCK:代表是一级位图
0x05000009 Length: 8:代表该快的二进制位数为9,长度为8的一个EXTENT归它管理。
Metadata:代表是保留信息,不可以被其他数据块占用的。
Unformatted:代表尚未格式化的信息。
parent dba: 0x0500000a:代表父级别管理头部位置a,代表10。
Highwater:: 0x0500000c:代表高水位块的编号为c,代表12,所以此时要APPEND或者SQLLOADER就会从块编号13开始。
Scn:SCN号码是导出时这个数据块最新的SCN号码。
同理导出10:
SQL> alter system dump datafile 20 block 10;
系统已更改。
发现相应参数是:
SECOND LEVEL BITMAP BLOCK:代表是二级位图。
L1 Ranges : 下面列表代表它管理的所有管理EXNTET的一级位图,因为表默认有一个所以默认有一条数据。
导出11后,发现参数:
SQL> alter system dump datafile 20 block 11;
系统已更改。
PAGETABLE SEGMENT HEADER:代表是头部。
此时插入一条数据:
SQL> insert into tt select * from emp WHERE ROWNUM=1;
已创建14行。
SQL> select dbms_rowid.rowid_block_number(rowid) from tt;
DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
------------------------------------
14
按照道理,数据应该从第12块开始写入,这里不是,说明自动管理并不是按照顺序插入了,头部块在第三块,插入位置是剩余空块的随机找,找到一个写满一个再写下一个,因为一级位图保存了块的使用情况的目录结构,那么看下一级位图在插入后变成什么了?
SQL> alter system dump datafile 20 block 9;
系统已更改。
其余的没有变化,这部分变化了:
0:Metadata 1:Metadata 2:Metadata 3:75-100% free
4:75-100% free 5:75-100% free 6:75-100% free 7:75-100% free
从第四个块开始从unformated变成了free,而free基本全部是75~100%,为什么呢?我们再继续插入点数据看下有没有变化:
SQL> insert into tt select * from tt;
已创建14行。
SQL> /
已创建28行。
SQL> /
已创建56行。
SQL> commit;
提交完成。
SQL> alter system dump datafile 20 block 9;
系统已更改。
此时发现变样子了:
0:Metadata 1:Metadata 2:Metadata 3:75-100% free
4:75-100% free 5:25-50% free 6:75-100% free 7:75-100% free
我们再插入点数据看下:
0:Metadata 1:Metadata 2:Metadata 3:75-100% free
4:75-100% free 5:FULL 6:50-75% free 7:75-100% free
数据满了,在插入就要使用其他的块了,说明:
1、自动管理的数据块不在使用精确的百分比作为使用量,而是使用1/4的范围管理,这样来降低开销。
2、自动管理不在使用链表来串联,而是树结构来管理表。
那么二级位图来做下试验:
因为二级位图是管理多个EXTENT,所以我们就将表放大就可以了,也不用插入什么数据:
SQL> alter table tt allocate extent(size 5m);
表已更改。
SQL> alter system dump datafile 20 block 10;
系统已更改。
发现LIST Ranges变化为:
L1 Ranges :
--------------------------------------------------------
0x05000009 Free: 5 Inst: 1
0x05000089 Free: 5 Inst: 1
0x0500008a Free: 5 Inst: 1
0x05000109 Free: 5 Inst: 1
0x0500010a Free: 5 Inst: 1
0x05000189 Free: 5 Inst: 1
0x0500018a Free: 5 Inst: 1
0x05000209 Free: 5 Inst: 1
0x0500020a Free: 5 Inst: 1
0x05000289 Free: 5 Inst: 1
0x0500028a Free: 5 Inst: 1
此时发现除第一个被管理的块(就是默认的哪个区,因为比较小,不需要两个块来管理),其余的都是成对出现,我们看下这个表所占用的区吧:
SQL> select EXTENT_ID,BLOCK_ID from dba_extents where segment_name='TT';
EXTENT_ID BLOCK_ID
---------- ----------
0 9
1 137
2 265
3 393
4 521
5 649
这里第一个EXTENT不用多说,第二个为137,换算为16进制数据就是89,89+1=8a。以此类推,可见除第一个EXNTENT以外,每个EXTENT前面都有位图块,这些位图块被第一个EXTENT的二级位图管理,他只能保存一千个左右,当超过这个数据,就会请求头部帮忙,再帮不过来,就建立一个父亲节点,建立树结构来存储。
由于篇幅所限,这里不能再写了,其余的可以继续做相关实验推敲,即可搞明白,对于逻辑架构中最关键和最复杂的SGEMENT以及一些常用的表空间容量的管理知识其实本文已经测试中用过一些,不过在下一次一起总结。
1、BLOCK是逻辑的,绝大部分情况下操作系统块的整数倍。
2、创建表空间时决定其大小,若不指定,采用系统的DB_BLOCK_SIZE为默认大小,而创建数据库默认参数大小为8K,OLTP系统可以降低一点,OLAP系统中可以增大一点,后面再说明块的内核结构的时候,会说明为什么。
3、块内部也有头部(和一个表的头部不要混淆,对于一个表的头部,会在SEGMENT专门说明),头部存放的是块内部的目录、SCN号码、TX修改事务、TYPE类型,即那一块存放在那里,因为ROWID其实也是逻辑的,在块内部是随机存放的,所以需要记录实际的物理位置,而由于其目录规则的要求、以及内存存放结构,在一个8K数据块中最多只能存储740条左右的数据;而其目录存放规则是从上向下码放。
4、数据部分是从下向上码放,和头部夹杂部分为空闲区域,后面详细说明。
5、这里说的块都是堆表的,所谓堆表就是插入到数据块那个位置是随机的,我们是通过ROWID来找到位置的。
一行数据的存储规则为:
1、行的头部,每一行有一个头部代表是一行的开始。
2、列宽度+列值。
3、跨块目标ROWID,数据块存放不下的时候,就会形成跨块,这种在结构设计上是很忌讳的。
4、数据仓库中,大量读取操作,一行内部存储的数据较多,所以将块设置大一些,可以存放更多的数据,否则块就会非常多,造成过多的IO;而OLTP系统中更多的是频繁的修改数据,即对块的征用,而要求对块的利用率要求较高,此时块可以适当多一些来达到这种效果。