Oracle内核技术揭密. 1.1 区:表空间中的基本单位

1.1 区:表空间中的基本单位

区,Extent,逻辑上连续的空间。它是表空间中空间分配的基本单位。如果在某表空间中创建一个表,哪怕只插入一行,这个表至少也会占一个区。

具体来讲,在Oracle 10g中,如果创建一个新表,初始至少为这个表分配一个区。而在Oracle 11.2.0.3以上版本中,创建新表时默认一个区都不会分配,也就是说,这个表此时不占存储空间。只有在向表中插入第一行数据时,才会默认为表分配第一个区。

无论是Oracle 10g还是Oracle 11GR2,如果表原有区中的空间用完了,Oracle就会默认为表一次分配一个区的空间。

可以通过DBA_EXTENTS数据字典视图查看表所属区。假设有一个表Table1,想要查询它所在的区,可通过如下方式:

select extent_id, file_id, block_id, blocks
from dba_extents where

segment_name='TABLE1' order by extent_id;

上面语句中,每个列的意义都很简单,这里不再介绍,如有问题,可以查看Oracle联机文档Oracle  Database Reference中的视图介绍。

说了这么多,大家会不会有一个疑问:既然区这么重要,是空间分配的基本单位,那么,区的大小是如何定义的呢?

Oracle专门设定了两种类型的表空间:统一区大小表空间和系统管理区大小表空间。区的大小就是由这两种表空间决定的。下面,先从统一区大小讲起。

1.1.1 统一区大小表空间和区的使用规则

统一区大小的表空间理解起来很简单,顾名思义,就是创建表空间时,设定区大小为一个统一的值。如下命令创建一个区大小为1MB的表空间:

create tablespace tbs_ts1 datafile '/u01/Disk1/tbs_ts1_01.dbf'
size 50m uniform size 1m;

tbs_ts1表空间包含一个50MB的数据文件,区大小为1MB。在此表空间中创建一个测试表:table1,观察一下区大小。

SQL> create table table1(id int,name
varchar2(20)) tablespace tbs_ts1;

Table created.

 

SQL> insert into table1values(1,'VAGE');

 

1 row created.

 

SQL> commit;

 

Commit complete.

 

SQL> select extent_id, file_id,
block_id, blocks from dba_extents where

segment_name='TABLE1' order by extent_id;

EXTENT_ID   
FILE_ID   BLOCK_ID     BLOCKS

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

0           
4         128          128

可以看到,table1表目前只包含一个区,它从4号文件的第128号块开始,大小为128个块。笔者这里的块大小为8KB,128个块,正好就是1MB。

从上面的结果可以看到,表table1从4号文件的128号块开始占用空间。从128~257号块是table1的第一个区,那么,0~127号块又是干什么用的呢?

事实上,每个文件的前128个块,都是文件头,被Oracle留用了。在Oracle 10g中是0至8号块被Oracle留用。而从Oracle 11GR2开始,一下就留用128个块,真是大手笔,不是吗?

这一部分文件头又分两部分,其中0号、1号块是真正的文件头,2~127号块是位图块。而在Oracle10g中,2~8号块则是位图块。

这个位图块又是干什么用的呢?

很容易理解,是用来记录表空间中区的分配情况的。位图块中的每一个二进制位对应一个区是否被分配给某个表、索引等对象。如果第一个二进制位为0说明表空间中第一个区未分配,如果为1说明已分配;第二个二进制位对应第二个区,以此类推,如图1-1所示。

 

图1-1 位图块示意图

在图1-1中,上面的二进制位就是位图块中的数据,下面表格表示区,其中灰色区是已分配区,白色区是未分配区。第1个区对应的二进制位是1,代表此区已分配,第2个区对应的二进制位是0,表示此区未分配,等等。

位图块又分两部分,其中第一个位图块又被当作位图段头,可以在DUMP文件中找到Oracle对此块类型的说明:Bitmapped File Space Header。从第二个位图块也就是3号块开始,就是真正的位图数据了,DUMP文件中这些块的类型说明为:Bitmapped File Space Bitmap。

关于位图块的DUMP格式描述,大家可以在网上找一下,此处不赘述。下面讨论一个网上较少讨论的话题:当要分配区时,Oracle如何在位图块中搜索可用区。

大家可以考虑一个问题,如果块大小为8KB,0号、1号块是文件头,2号块是位图头,在Oracle 10g中,3~8号块是位图数据块,共6个位图块,大小是48K字节,每个字节8个二进制位,一共393216个二进制位。每个二进制位对应一个区,一共就393216个区。如果是Oracle 11GR2,这个数字又要多出好多倍。那么,如果某个表要在数据文件中分配一个新区,Oracle如何在这30多万个二进制位中,确定哪个二进制位对应的区可以分配给表呢?

Oracle用的方法其实很简单,在位图块中,找一个标记位,如果0~2号区被占用了,标记位的值为3;如果3~4号区又被占用了,标记位增加为5。假设此时2号区被释放了,标记位变为2。

如果需要分配新的区,从这个标记位处开始查找即可。假设目前标记位值为5,有进程需要4个未分配区,Oracle就从5号区开始向下查找。

需要注意的是,如果开启了闪回Drop,而且Drop了表,那么,区并不会被释放,因此标记位不会下降。因为Drop只是改名,而并不会真正删除表。

1.1.2 系统管理区大小

刚才介绍了统一区大小,并且测试了区的分配规则。在系统管理区中,区的分配规则是一样的,但是,区大小的设定不再由人为决定,Oracle会根据表大小自动设置。

Oracle如何设定区大小呢?只需要创建一个表空间,并进行很简单的测试,就能搞明白这点。命令如下所示:

create tablespace tbs_ts2 datafile
'/u01/Disk1/tbs_ts2_01.dbf' size 50m reuse;

上面的命令创建了一个tbs_ts2表空间,至于区大小的管理方式,这里没有指定,这样Oracle默认创建的,就会是系统管理区的大小。

现在在tbs_ts2中创建表,并观察它的区大小。

SQL> create table table_lhb1(id int,name
varchar2(20)) tablespace tbs_ts2;

Table created.

 

SQL> select extent_id, file_id,
block_id, blocks from dba_extents where segment_

name='TABLE_LHB1' order by extent_id;

 

 EXTENT_ID   
FILE_ID   BLOCK_ID     BLOCKS

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

        
0          5        128          8

可以看到TABLE_LHB1目前有一个区,大小只有8个块,也就是64KB。插入一些数据,将表撑大点再观察。

SQL> insert into table_lhb1 select
rownum,'aaa' from dba_objects;

 

12650 rows created.

 

SQL> select extent_id, file_id,
block_id, blocks from dba_extents where segment_

name='TABLE_LHB1' order by extent_id;

 

 EXTENT_ID   
FILE_ID   BLOCK_ID     BLOCKS

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

        
0          5        128          8

        
1          5        136          8

        
2          5        144          8

        
3          5        152          8

上面向表中插入了12650行,表目前涉及4个区,每个区都是8个块64KB。提交后继续插入,命令如下:

SQL> insert into table_lhb1 select *
from table_lhb1;

 

12650 rows created.

 

SQL> insert into table_lhb1 select *
from table_lhb1;

25300 rows created.

 

SQL> insert into table_lhb1 select *
from table_lhb1;

 

50600 rows created.

 

SQL> insert into table_lhb1 select *
from table_lhb1;

 

101200 rows created.

 

SQL> commit;

 

Commit complete.

 

SQL> select extent_id, file_id,
block_id, blocks from dba_extents where segment_

name='TABLE_LHB1' order by extent_id;

 

 EXTENT_ID   
FILE_ID   BLOCK_ID     BLOCKS

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

        
0          5        128          8

        
1          5        136          8

        
2          5        144          8

        
3          5        152          8

        
4          5       
160          8

        
5          5        168          8

        
6          5        176          8

        
7          5        184          8

        
8          5        192          8

        
9          5        200          8

       
10          5        208          8

       
11          5        216          8

       
12          5        224          8

       
13          5        232          8

       
14          5        240          8

       
15          5        248          8

       
16          5        256        128

       
17          5        384        128

 

18 rows selected.

多次插入后,表已经占了很多空间,我们来看一下现在区的使用情况。0~15号区,大小为8个块64KB,从第16号区开始,区大小变为了128个块1MB大小。也就是说,表的大小小于1MB时,表的每个区都是64KB,当表的大小超过1MB,再分配新区时,区的大小将是1MB。读者可以继续测试,当表进一步变大,区大小将会变成8MB,表继续扩大,更大的区也有,这里就不测了。

可见,在系统管理区大小表空间中,区的大小随表的增大而增大。

到这里,我们已经发现了系统管理区大小的秘密。很简单吧?有时候探索Oracle也不是件复杂的事情,只要多动手就行了。我在做培训的时候,也常跟学员讲:探索的过程,就是熟悉Oracle的过程。你探索出的结果不一定很有用,但探索的过程,会加深对Oracle的熟悉程度,这才是研究、探索Oracle的真正目的。研究Oracle,很多时候结果不是目的,过程更有意义。

我们已经了解了统一区大小和系统管理区大小的不同,那么,什么时候使用统一区大小,什么时候使用系统管理区大小呢?

从空间的利用率上讲,小区节省空间,大区可能会浪费空间。比如,当区大小是10MB时,为一个表分配了一个10MB的区,哪怕它只使用了这10MB中的1个字节,这10MB空间也完全属于这个表了,其他表无法再使用这部分空间。从这个角度上讲,小区的空间利用率无疑是高的。

但从性能角度上讲,对于随机访问,大区、小区没有影响。但对于全表扫描这样的操作,大区又是更合适的。因为连续空间更多,可以减少磁头在区间的定位。

在系统管理区大小的方式下,当表比较小时,区也比较小,当表大时,区也随之变大,这种方式无疑可以在空间的利用率、全扫描的性能之间找到一种平衡。因此建议大多数情况下,都可以采用系统管理区大小的方式。除非有某个表,已明确地知道它会很大,为了保证全扫描的性能,直接建一个统一区大小,并且区比较大的表空间,以便将表存放其中。

如果使用统一区大小,几百KB甚至1MB的区,都有点小。其实可以参考系统管理型的表空间,当段的大小超过64MB时,区大小为8MB。在使用统一区大小时,也可以将所有区都固定为8MB。

我见到过很多数据库都使用统一区大小,而且其大小为1MB。原因是在大部分的操作系统中,一次I/O操作的最大的读、写数据量是1MB。即使使用8MB的区,一个区也必须分8次进行I/O操作,超过1MB的区大小,并不能减少I/O操作的次数。

但是,我们要考虑一点,8MB的区连续的空间更多。读取8MB内的第1MB和第2MB数据虽然必须要分两次I/O操作,但这两次I/O操作很可能是连续I/O,因为第1MB和第2MB数据有可能是相连的。如果区大小仅为1MB,虽然读取表的第1区和第2区也是两次I/O操作,但这两次I/O操作很可能不相连,是随机I/O操作。连续I/O操作的性能当然比随机I/O操作的要高。

因此,出于全表扫描性能的考虑,即使使用统一区大小,大点的区(如8MB大小)是很合适的选择。

还有一个问题,不知道大家有没考虑到。这个问题涉及统一区大小表空间的位图块。每个二进制位对应一个区的使用情况,这是没问题的,但系统管理区大小呢?就比如刚才创建的TABLE_LHB1表,前16个区大小为64KB,之后的区大小为1MB。区的大小不同,如何用二进制位来反映区的使用情况呢?

Oracle的处理方法是这样的,以64KB(也就是8个块)为准,每个二进制位对应64KB。1MB的区,对应16个二进制位。每分配一个1MB的区,Oracle将对应的16个二进制位(也就是两个字节)设置为1。释放一个区也同样,将16个二进制位设置为0。这样就解决了区大小不统一的问题,Oracle的解决方法还是很巧妙的!

1.1.3 碎片:少到可以忽略的问题

最后,来想这样一个问题:在表空间级别有碎片吗?

答案是:有,但也要看情况。在统一区大小表空间中,因为区的大小一致,不会出现碎片问题。但在系统管理区中,由于区的大小不一致,仍会存在碎片。比如说,有很多个64KB的区,互相不连续,分布在数据文件的各个角落。当需要1MB、8MB大小的区时,这些不连续的64KB区无法被重用,这就是典型的碎片了。但是,这种情况很少出现。因为区不会被频繁地分配、释放。一个表创建之后,很少会去对它进行Drop、Truncate操作。

没有频繁的分配、释放操作,碎片也就很少出现了。所以,在表空间层,碎片已经是一个可以忽略的问题了。当然,在表层、索引层,还有可能存在碎片。

时间: 2024-09-15 11:51:35

Oracle内核技术揭密. 1.1 区:表空间中的基本单位的相关文章

Oracle内核技术揭密

数据库技术丛书 Oracle内核技术揭密 吕海波 著 图书在版编目(CIP)数据 Oracle内核技术揭密/吕海波著. -北京:机械工业出版社,2014.7 (数据库技术丛书) ISBN 978-7-111-46931-5 I.O- II.吕- III. 关系数据库系统 IV. TP311.138 中国版本图书馆CIP数据核字(2014)第115943号 本书是首本国内作者深入剖析Oracle原理的技术书籍.虽以内部原理为主线,但又不乏很多实际的应用案例,希望读者可以将学到的原理与实际应用相结合

Oracle内核技术揭密. 导读

Preface前 言 美国有一句著名的谚语:如果上帝关闭了一扇门,他会为你打开一扇窗.美国还有一个有名的关于Oracle的笑话:上帝和埃里森的区别就是,上帝不认为自己是埃里森. 无论上帝怎么想,埃里森肯定认为自己是上帝,至少,是数据库界的上帝.这位数据库界的上帝所开创的著名的Oracle数据库软件是闭源的,对于想研究Oracle的DBA来说,相当于关上了一扇门.但同时Oracle中提供大量的DUMP命令,这又相当于为DBA打开了一扇窗.但现在,这扇窗正在慢慢关闭. 很早之前,有很多从Oracle

Oracle内核技术揭密. 1.2 段中块的使用

1.2 段中块的使用 在讲解本节主题前,我们先来理清一个概念,什么是段.在Oracle中,表和段是两个截然不同的概念.表从逻辑上说明表的形式,比如表有几列,每列的类型.长度,这些信息都属于表.而段只代表存储空间,比如,上节中提到的区,就是属于段.一个段中至少要包含一个区. Oracle中,每个对象都有一个ID值,表有表的ID,段有段的ID.在DBA_OBJECTS数据字典视图中,object_id列是表ID,data_object_id列是段ID,下面查看了某个表的表ID和段ID: SQL> c

Oracle技术:使用rman进行表空间基于时间点的恢复

实例说明: (1)先创建2个表空间. create tablespace user01 datafile '+DG1' size 1M; create tablespace user02 datafile '+DG1' size 1M; (2)在每个表空间上各创建一张表. create table scott.customers (cust_id int,cust_name varchar2(10)) tablespace user01; create table scott.sales (id

表空间 数据文件-oracle数据库表空间中的数据文件自动扩展到32G后不再自动扩展

问题描述 oracle数据库表空间中的数据文件自动扩展到32G后不再自动扩展 CSDN移动问答oracle表空间中的数据文件自动扩展到32G后不再自动扩展,报ora-01653错误,我之后手动加了个数据文件,但是不久之后这个数据文件自动扩展到了32G又报错,请问这是什么原因,难道以后只能手动添加数据文件么????

安装Oracle后,经常使用的修改表空间的SQL代码

oracle 配置:Windows NT 4.0 中文版5块10.2GB SCSI硬盘分:C:盘.D:盘.E:盘.F:盘.G:盘Oracle 8.0.4 for Windows NTNT安装在C:\WINNT,Oracle安装在C:\ORANT 目标:因系统的回滚段太小,现打算生成新的回滚段,建立大的.新的表空间(数据表空间.索引表空间.回滚表空间.临时表空间.)建两个数据表空间.两个索引表空间,这样建的目的是根据实际应用,如:现有10个应用用户,每个用户是一个独立子系统(如:商业进销存MIS系

oracle手工完全恢复(三) 恢复表空间

案例2: recover tablespace(恢复表空间(删除了tablespace的所有的datafile)) 在关库状态下删除数据文件时,这样恢复:转储datafile,使丢失的datafile脱机, recover tablespace (1)模拟环境 SQL> conn scott/tiger Connected. SQL> col tname for a30 SQL> select * from tab; TNAME                          TABT

Oracle备份数据导入到其他的表空间(只设置默认表空间无效)

  我们在导入一个Oracle备份的数据文件(*.dmp)到另外一个数据库的用户下时,如果需要更换表空间,可以采用下几个办法. 假设导出用户名:EXP_USER 表空间为:EXP_TSPACE 导入用户名:IMP_USER 表空间为:IMP_TSPACE 1.设置导入用户的默认表空间以及权限. a)建表语句如下: create user IMP_USER Sql代码 identified by "密码" default tablespace IMP_TSPACE temporary t

ORACLE RAC 裸设备数据库一节点表空间扩容错误添加数据文件到本地的处理

    9月2日上午,总部CRM求助,问题是ORACLE 10.2.0.4 RAC 裸设备数据库在表空间扩容时操作失误,将数据文件错误添加成文件系统文件并且还在节点1的本地目录,导致节点2无法完成写操作,报错信息如下: Wed Sep  2 08:23:23 2015 Errors in file /oracle/app/admin/oracrm/bdump/oracrm2_dbw0_2101996.trc: ORA-01157: cannot identify/lock data file 1