1. Tablespace 表空间

1.1 TBS 的分类
PERMANENT #永久 TBSUNDO #撤销 TBSTEMPORARY #临时 TBS
1.2 TBS 的管理方式
重点是段的管理方式和区的管理方式是在建立 TBS 时确定的。
1.2.1 段管理方式
有AUTO
和MANUAL
两种
1.2.2 区管理方式
本地管理(locally managed
)
SQL> select tablespace_name,contents,extent_management,segment_space_management from dba_tablespaces;TABLESPACE_NAME CONTENTS EXTENT_MAN SEGMEN--------------- ----------- ---------- -------SYSTEM PERMANENT DICTIONARY MANUALSYSAUX PERMANENT LOCAL AUTOTEMP TEMPORARY LOCAL MANUALUSERS PERMANENT LOCAL AUTOEXAMPLE PERMANENT LOCAL AUTOUNDO_TBS01 UNDO LOCAL MANUALTMP01 TEMPORARY LOCAL MANUALTBS_16K PERMANENT LOCAL AUTO
1.3 创建 TBS
1.3.1 建立缺省值的 TBS
SQL> create tablespace a datafile '/u01/app/oracle/oradata/orcl/a01.dbf' size 10m;-- 利用oracle的dbms_metadata.get_ddl包查看缺省值SQL> set serverout onSQL> declare aa varchar2(2000);beginselect dbms_metadata.get_ddl('TABLESPACE','A') into aa FROM dual;dbms_output.put_line(aa);end;/-- 结果:CREATE TABLESPACE "A" DATAFILE '/u01/app/oracle/oradata/orcl/a01.dbf' SIZE 10485760LOGGING ONLINE PERMANENT BLOCKSIZE 8192EXTENTMANAGEMENT LOCAL AUTOALLOCATE DEFAULTNOCompress SEGMENT SPACE MANAGEMENT AUTOPL/SQL procedure successfully completed.
1.3.2 建立手动管理的 TBS
SQL> create tablespace b datafile '/u01/app/oracle/oradata/orcl/b01.dbf' size 10m extent management local uniform size 128k segment space management manual;-- 调dbms_metadata.get_ddl包看oracle对该语句的ddl操作是:set serverout onSQL> declare aa varchar2(2000);beginselect dbms_metadata.get_ddl('TABLESPACE','B') into aa FROM dual;dbms_output.put_line(aa);end;/CREATE TABLESPACE "B" DATAFILE'/u01/app/oracle/oradata/orcl/a01.dbf' SIZE 10485760LOGGING ONLINE PERMANENT BLOCKSIZE 8192EXTENTMANAGEMENT LOCAL UNIFORM SIZE 131072 DEFAULTNOCompress SEGMENT SPACE MANAGEMENT MANUAL-- 信息说明是: 区本地管理且统一分配128K, 段手动管理.
1.4 查看 Table 对应的 TBS
SQL> select table_name,tablespace_name from user_tables where table_name='EMP';TABLE_NAME TABLESPACE_NAME--------- ---------------EMP USERS
1.5 查看 TBS 对应的数据文件
SQL> col tablespace_name format a10SQL> col file_name format a45SQL> select tablespace_name, file_id,file_name, round(bytes/(1024*1024),0) total_space from dba_data_files order by tablespace_name;TABLESPACE_NAME FILE_ID FILE_NAME TOTAL_SPACE--------------- ------ ------------------------------------------ -------------EXAMPLE 5 /u01/app/oracle/oradata/orcl/example01.dbf 1244KLAUS 8 /u01/app/oracle/oradata/orcl/klaus01.dbf 100SYSAUX 3 /u01/app/oracle/oradata/orcl/sysaux01.dbf 990SYSTEM 1 /u01/app/oracle/oradata/orcl/system01.dbf 810TBS_16K 7 /u01/app/oracle/oradata/orcl/tbs16k01.dbf 10TEST 2 /u01/app/oracle/oradata/orcl/test01.dbf 10UNDOTBS1 4 /u01/app/oracle/oradata/orcl/undotbs01.dbf 100USERS 6 /u01/app/oracle/oradata/orcl/users01.dbf 620
1.6 删除 TBS
SQL> drop tablespace tbs_name including contents and datafiles;
查看 TBS 空闲大小
SQL> select TABLESPACE_NAME,sum(bytes)/1024/1024 from dba_free_space group by tablespace_name;TABLESPACE_NAME SUM(BYTES)/1024/1024-------------- ------------------UNDOTBS1 98.4375SYSAUX 14.625USERS 48.1875SYSTEM 1.875EXAMPLE 31.25
1.7 大文件 (bigfile) TBS (默认 small file)
-- small file :在一个 TBS可以建立多个数据文件-- bigfile :在一个 TBS只能建立一个数据文件 (8k的block ,datafile maxsize 可以 32T),可以简化对数据文件管理SQL> create bigfile tablespace big_tbs datafile '/u01/app/oracle/oradata/orcl/bigtbs01.dbf' size 100m;-- 试图在该 TBS下增加一个数据文件会报错SQL> alter tablespace big_tbs add datafile '/u01/app/oracle/oradata/orcl/bigtbs02.dbf' size 100m;alter tablespace big_tbs add datafile '/u01/app/oracle/oradata/orcl/bigtbs02.dbf' size 100m*ERROR at line 1:ORA-32771: cannot add file to bigfile tablespace-- 查看大文件 TBS:SQL> select name,bigfile from v$tablespace;NAME BIG--------- --------SYSTEM NOUNDOTBS1 NOSYSAUX NOUSERS NOTEMP NOEXAMPLE NOTBS_16K NOBIG_TBS YES
2. SEGMENT (段)
2.1 SEGMENT 概述
TBS 在逻辑上可以对应多个段,物理上可以对应多个数据文件,一个段SEGMENT
比较大时可以跨多个数据文件 Data File。
段中至少有一个初始的区extent
。当 SEGMENT 的数据增加,区extent
不够时,将为这个段SEGMENT
分配新的区。
2.2 段的两种管理方式
ASSM自动管理方式(Auto Segment Space Management
) (缺省)
2.3 表和段 (segment) 的关系
一般一个单纯的表就分配一个段,但往往表上经常会有主键约束,那么就会有索引,索引有索引段,还有分区表,每个分区会有独立的段。再有就是 oracle 的大对象, 如果表里引用blob
,clob
,那么这个表就又被分出多个段来。
SQL> conn / as sysdbaSQL> create user klaus identified by klaus;SQL> grant connect,resource to klaus;SQL> conn klaus/klausSQL> select * from user_segments;no rows selectedSQL> create table t1 (id int);
从 11GR2 开始默认创建的表不会立即分配segment
,不会占用磁盘空间,当第一条数据insert
时才会分配空间。
SQL> select segment_name from user_segments;no rows selectedSQL> conn / as sysdbaSQL> grant insert on klaus.t1 to klaus;Grant succeeded.SQL> grant unlimited tablespace to klaus;Grant succeeded.SQL> conn klaus/klausSQL> insert into t1 values(1);SQL> select segment_name from user_segments; -- 只建立一个表时,一个表对应一个段SEGMENT_NAME-----------------------T1SQL> create table t2 (id int constraint pk_t2 primary key, b blob, c clob);SQL> insert into t2 values(1,rawtohex('klaus'),rawtohex('yao'));SQL> select segment_name, segment_type from user_segments; -- 表添加了主键约束,有了索引,添加了大对象,则分配多个段SEGMENT_NAME SEGMENT_TYPE----------------------- -------------------------PK_T2 INDEXSYS_IL0000095333C00002$$ LOBINDEXSYS_IL0000095333C00003$$ LOBINDEXSYS_LOB0000095333C00002$$ LOBSEGMENTSYS_LOB0000095333C00003$$ LOBSEGMENT -- 大对象特殊,有两个段T2 TABLET1 TABLE
2.4 延迟段创建
2.4.1 概述
Oracle 11gR2 又增加了一个新的初始化参数DEFERRED_SEGMENT_CREATION
(仅适用未分区的heap table
),此参数设为TRUE
后,create table
后并不马上分配segment
,实际的表段 (Table Segement
) 被延迟到第一行数据插入时创建。延迟段创建可以节省空间,加快初始化过程,是面向性能和资源的一个优化,这对于应用程序的部署可能有些好处。也可以使局部设置改变这一功能 (覆盖DEFERRED_SEGMENT_CREATION
),在create table
语句时加上SEGMENT CREATION
子句指定。如:
-- 指定表空间create table scott.t1(id int,name char(10)) SEGMENT CREATION IMMEDIATE TABLESPACE TB1;-- 默认表空间-- 或延迟创建create table scott.t1(id int,name char(10)) SEGMENT CREATION IMMEDIATE;-- 缺省在11gR2create table scott.t1(id int,name char(10)) SEGMENT CREATION DEFERRED;
2.4.2 产生的问题及解决
该新特性会带来一个问题:在使用exp/imp
进行导出导入时,不会包含这些空表 (数据泵expdp
不存在这个问题,expdp
可以导出空表),所以,在迁移数据的时候可能会导致遗漏部分空表。针对这个问题的解决方法有:
2.4.3.1 Insert:
INSERT
一行,再ROLLBACK
或者删除就可以产生SEGMENT
了。该方法是在空表中插入数据,再删除,则会产生SEGMENT
,此时再导出时就可以导出空表。
2.4.3.2 设置 DEFERRED_SEGMENT_CREATION 参数
设置DEFERRED_SEGMENT_CREATION
参数为FALSE
来禁用 ”延迟段创建”,无论是空表还是非空表,都会分配SEGMENT
。
提示需要注意的是,该值设置后只对后面新增的表产生作用,对于之前建立的空表 (已经存在的) 不起作用,仍不能导出。
2.4.3.3 使用 ALLOCATE EXTENT
使用ALLOCATE EXTENT
可以为数据库的每一张表分配EXTENT
。批量生成脚本:
-- 注意修改用户名SELECT 'ALTER TABLE '||D.OWNER||'.'||D.TABLE_NAME||' ALLOCATE EXTENT;'EXEC_SQL FROM DBA_TABLES D WHERE D.SEGMENT_CREATED='NO' AND D.OWNER IN ('BDC','ABC');
执行以上 SQL 产生的脚本后即可为每一个空表分配段,然后执行 exp 命令即可。
2.5 立即分配段
-- 指定表空间create table scott.t1(id int,name char(10)) SEGMENT CREATION IMMEDIATE TABLESPACE TB1;-- 默认表空间create table scott.t1(id int,name char(10)) SEGMENT CREATION IMMEDIATE;
3. EXTENT (区)
3.1 EXTENT (区) 的概述
区是 ORACLE 进行存储空间分配的最小单位。是由一系列逻辑上连续的 Oracle 数据块组成的逻辑存储结构。段中第一个区叫初始区,随后分配的区叫后续区。当段中所有的空间使用完后,ORACLE 自动为该段分配新的区。区不可以跨越多个数据文件或者段。Data blocks in an extent are logically contiguous but can be non-contiguous on disk:逻辑块连续、物理块可以是非连续的。The blocks of a newly allocated extent,although free,may have been used before.
3.2 区的管理方式
本地管理:在每个数据文件中使用位图管理空间的分配。TBS 中所有区 (extent
) 的分配信息都保存在该 TBS 对应的数据文件的头部。
优点:速度快,存储空间的分配和回收只是简单地改变数据文件中的位图,而不像字典管理方式还需要修改数据库。无碎片,更易于 DBA 维护。
3.3 表和区 (extent) 的关系
建立表的时候建立段 (11gR2 默认延迟创建段),然后自动分配相应的extent(1 个或多个),亦可以手工提前分配extent(用于需大量插入数据的表)。也就是说,在这个对象创建以后,ORACLE 至少给它分配一个区,初始大小是 64K,一个标准块的大小是 8K,刚好是 8 个BLOCK。
3.4 查看段的初始区
3.4.1 初始区 ID 为 0
-- sys:SQL> drop tablespace test including contents and datafiles;SQL> drop table scott.t1 purge;SQL> create tablespace test datafile '/u01/app/oracle/oradata/orcl/test01.dbf' size 10m;SQL> create table scott.t1 tablespace test as select * from scott.dept;SQL> col segment_name for a15;SQL> select segment_name,file_id,extent_id,bytes from dba_extents where segment_name='T1';SEGMENT_NAME FILE_ID EXTENT_ID BYTES------------ ------- --------- --------T1 6 0 65536T1 6 0 65536-- 可以看到段T1的初始区ID为0,大小为 65536 bytes;
3.4.2 分配更多的区
-- 向表中插入数据,看Oracle为该段分配更多的区SQL> insert into scott.t1 select * from scott.t1;///…2048 rows created.SQL> select segment_name,file_id,extent_id,bytes from dba_extents where segment_name='T1';SEGMENT_NAME FILE_ID EXTENT_ID BYTES------------ ------- --------- --------T1 6 0 65536T1 2 0 65536T1 2 1 65536T1 2 2 65536-- 此时看到随着数据的插入,T1段动态扩展为四个区;
3.4.3 delete 表数据 extent 仍存在
SQL> delete scott.t1;4096 rows deleted.SQL> select segment_name,file_id,extent_id,bytes from dba_extents where segment_name='T1';
此时表段的数据已经删除,但所有extent
依然健在,无法回收 T1 段的所有区。
3.4.4 要求预分配的区空间
可以要求一个预分配所需要的空间 (但要注意,所要的空间 一定是在 TBS 可达到的size
范围内)。
-- 如EXTENT_ID:3-7是预分配的空间SQL> alter table scott.t1 allocate extent (datafile '/u01/app/oracle/oradata/orcl/test01.dbf' size 5m);SQL> select segment_name,file_id,extent_id,bytes from dba_extents where segment_name='T1';SEGMENT_NAME FILE_ID EXTENT_ID BYTES------------ ------- --------- --------T1 6 0 65536T1 2 0 65536T1 2 1 65536T1 2 2 65536T1 2 3 1048576T1 2 4 1048576T1 2 5 1048576T1 2 6 1048576T1 2 7 1048576
3.4.5 回收未使用过的 extent
回收free extent
, 使用deallocate
。只能收回从未使用的 extent
。
SQL> alter table scott.t1 deallocate unused;Table altered.SQL> select segment_name,file_id,extent_id,bytes from dba_extents where segment_name='T1';SEGMENT_NAME FILE_ID EXTENT_ID BYTES------------ ------- --------- --------T1 6 0 65536T1 2 0 65536T1 2 1 65536T1 2 2 65536
3.5 表对应的数据文件和 TBS
-- 如何查看一个表所对应的数据文件及 TBS ?-- 抓住上面dba_extents中的file_id字段(user_extents里没有这个字段),然后:SQL> col file_name for a45;SQL> select file_id,file_name,tablespace_name from dba_data_files;FILE_ID FILE_NAME TABLESPACE_NAME--------- ------------------------------------------ ---------------1 /u01/app/oracle/oradata/orcl/system01.dbf SYSTEM3 /u01/app/oracle/oradata/orcl/sysaux01.dbf SYSAUX4 /u01/app/oracle/oradata/orcl/undotbs01.dbf UNDOTBS16 /u01/app/oracle/oradata/orcl/users01.dbf USERS5 /u01/app/oracle/oradata/orcl/example01.dbf EXAMPLE7 /u01/app/oracle/oradata/orcl/tbs16k01.dbf TBS_16K8 /u01/app/oracle/oradata/orcl/a01.dbf A9 /u01/app/oracle/oradata/orcl/b01.dbf B2 /u01/app/oracle/oradata/orcl/test01.dbf TEST
4. BLOCK (数据块)
4.1 BLOCK (数据块) 概述
BLOCK是 Oracle 进行存储空间IO操作的最小单位;
data block:Oracle 11g 标准块:8k,支持 2-32k,由(block header+free space+data)组成。
BLOCK的管理方法是区的管理和段管理的具体体现:
4.2 BLOCK 管理方式
4.2.1 ASSM (位图)自动管理方式
如创建TBS
时区为本地管理方式,并且将段的存储空间方式设置为AUTO
(即ASSM
),该TBS
的所有块均采用位图自动管理方式,系统默认方式。
4.3 数据块头部
ITL #:事务槽,可以有多个ITL以支持并发事务# 每当一个事务要更新数据块里的数据时,必须先得到一个ITL槽,# 然后将当前事务ID,事务所用的undo数据块地址,SCN号,当前事务是否提交等信息写到ITL槽里Initrans #:初始化事务槽的个数,表默认1,index 默认为2;Maxtrans #:最大的事务槽个数(默认255)ROW DIR #:行目录,指向空闲行起始和结束的偏移量.NOTE #:使块头增加的可能情况是,row entries增加,增加更多的ITL空间.
4.4 空闲列表方式的数据块管理
4.4.1 Freelist
空闲列表中登记了可以插入数据的可用块,位置在段头,插入表行数据时首先查找该列表。
4.4.2 Pctfree
4.4.3 Pctused
一个块的使用水位的百分比,这个水位将使该块返回到可用列表中去等待更多的插入操作。达到该值,该块信息加入 freelist。Pctused 参数在 ASSM 下不使用。
1.建表时,注意 PCTFREE 参数的作用
PCTFREE:为一个块保留的空间百分比,表示数据块在什么情况下可以被insert,默认是 10,表示当数据块的可用空间低于 10% 后,就不可以被insert了,只能被用于update;
即:当使用一个 block 时,在达到pctfree之前,该block是一直可以被插入的,这个时候处在上升期
PCTUSED:是指当块里的数据低于多少百分比时,又可以重新被insert,一般默认是 40,即 40%,即:当数据低于 40% 时,又可以写入新的数据,这个时候处在下降期。
2.举例说明1
假设你一个块可以存放 100 个数据,而且PCTFREE是 10,PCTUSED是 40,则:不断的向块中插入数据,如果当存放到 90 个时,就不能存放新的数据,这是受pctfree来控制,预留的空间是给UPDATE用的。
当删除一个数据后,再想插入个新数据行不行?不行,必须是删除 41 个,即低于 40 个以后才能插入新的数据的,这是受pctused来控制的。
3.举例说明2
注意:如果 TBS 上启用了ASSM,在建立表的时候,只能指定 PCTFREE,否则可用指定PCTFREE和PCTUSED。
举例:比如一个块的pctfree定为 10%,pctused定为 40%(oracle 默认设置)。那么一个块的使用率达到90% (即1-10%) 的时候,oracle将该块从freelist中移除,停止使用该块来插入数据(但可更新)。
后来该块上发生了一些删除操作,使得该块的利用率下降,当使用率下降到 40% 以下的时候,oracle 重新将该块加入freelist,可用于新的插入
4.4.4 行链接 (row chaining)
指一行存储在多个块中的情况,这是因为该行的长度超过了一个块的可用空间大小,即行链接是跨越多块的行。
4.4.5 行迁移 (row migration)
指一个数据行由于update
语句导致当前块被重新定位到另一个块(那里有充足的空间),但在原始块中保留一个指针的情形。原始块中的指针是必需的,因为索引的ROWID
项仍然指向原始位置。
4.4.6 如何鉴定行链接或行迁移?
查看dba_tables
的AVG_ROW_LEN
列和CHAIN_CNT
列,当CHAIN_CNT
有值时,看AVG_ROW_LEN
,它表示行的平均长度(byte
)。
如果AVG_ROW_LEN
<块大小,则是迁移行,如果AVG_ROW_LEN
>块大小,则是链接行。
SQL> create table t1(c1 varchar2(20));SQL>beginfor i in 1..1000 loop insert into t1 values(null);end loop;end;/-- 分析t1表确定无行迁移SQL> analyze table t1 compute statistics;SQL> select pct_free,pct_used,avg_row_len,chain_cnt from user_tables where table_name='T1';PCT_FREE PCT_USED AVG_ROW_LEN CHAIN_CNT-------- -------- ----------- ---------10 3 0-- 填充这些空列,再分析t1,有了行迁移SQL> update t1 set c1='klausyao is my name';SQL> analyze table t1 compute statistics;SQL> select pct_free,pct_used,avg_row_len,chain_cnt from user_tables where table_name='T1';PCT_FREE PCT_USED AVG_ROW_LEN CHAIN_CNT-------- -------- ----------- ---------10 28 886-- move表,再分析t1,行迁移消失.-- 思考: 段重组对于行链接有效吗?SQL> alter table t1 move;SQL> analyze table t1 compute statistics;SQL> select pct_free,pct_used,avg_row_len,chain_cnt from user_tables where table_name='T1';PCT_FREE PCT_USED AVG_ROW_LEN CHAIN_CNT-------- -------- ----------- ---------10 21 0
逻辑结构:tablespace Segment extent block




