您的位置:首页 > 其它

基础学习--表的概念(一)

2010-04-19 10:54 176 查看
author:skate
time:2010-04-19

在优化数据库的时候,如果应用相对来来说很简单,没有复杂耗时的sql,要想大幅度提升数据库的性能(事务响应时间),就只能通过调整系统参数和表的存储参数了.所以最近要从底层总结下相关知识,也加深自己对oracle的基本概念的理解。




表的概念

我们当前环境都是用二维表来存储数据的,那表又是什么呢?Oracle是一种关系型数据库系统,在关系型数据库里,一组关系的实体化就组成了一张表。表里面有一个或多个字段,这些字段按着某种规则(称为关系,一般是业务规则)组成一个集合,这样的每一个关系,我们就成为一条记录或行。表是个十分重要的概念,无论是DBA还是研发人员大部分的工作就是和不同表打交道。
Oracle的表是如何存储的?oracle的表是按行来存储数据的。下面谈谈和存储有关的概念,oracle最小的存储单元是block(块),一般大小在2k-32k之间,默认是8k。这个oracle的block和os的block是不一样的,要远大于os的block,所以oracle的block不是io的基本单元,只是oracle的基本访问单元。对于oracle来说每个表空间都有一个唯一block大小,在oracle8i或更早版本中,整个数据库的所有表空间都有唯一block的大小,从oracle9i开始,不同的表空间可以拥有不同的表空间,因此参数db_block_size不在表示数据库块的大小,而是缺省表空间的大小。
Oracle的block的大小是最小访问单元,但他的值太小,如果表的存储按一个block一个block的大小分配,那效率太低了;为此oracle又引入了更大的单位extent(扩展),extent是oracle最小的分配单元,它是由连续的block组成的,oracle在给对象分配空间的时候,最少分配一个extent;extent由一个或多个block连续组成,这样连续是逻辑,在当下存储充分使用条带化条件下,不保证block物理也是连续的。
比extent更大的单位是segment,也就是我们常说的段,一组结构相同的extent就组成了一个segment,segment是存储在某个表空间的,表空间是个逻辑概念,一个表空间一般包括一个或着多个数据文件,也可以不包含数据文件,但这样的表空间是不同使用的。其实segment是存储在数据文件里,但是这种存储是按照表空间来组织的,一个段可能存储在一个数据文件中,也可能存储在多个数据文件中,不过这些数据文件必须属于同一个表空间。下面的图是一个很好的逻辑示意图:






表在Oracle数据库中就是存储在"Segment"里的。一张普通的表就对应一个SEGMENT,不过还有一些特例:

l 一张索引组织表可能包含了多个段,比如OVERFLOW段
l 一张表中,如果有LOB字段,那么LOB字段可能存储在独立的段中,那么这张表也可能包含多个段
l 一张分区表可能存储在N个独立的段中,这些段甚至可能存储在不同的表空间中
l 在一个CLUSTER(簇)中,可能存储多张表,而不是一张表。因此存储于簇中的表,表和SEGMENT不是一一对应的

通过上面的介绍大家知道了表的数据实际上是作为“段”的形式存储在表空间里的。当创建一个表的时候,Oracle自动会为这张表创建段,并分配第一个扩展(EXTENT)。我们已经知道了每个EXTENT是由多个连续的BLOCK组成的,数据就存储在这些BLOCK中,当这些BLOCK都使用完了,那么当下一次需要插入数据的时候,Oracle会自动为这张表扩展一个EXTENT。所以随着数据量的增长,这张表在不断的扩展。某张表的扩展的数量受到表空间容量和表的MAXEXTENTS参数的限制。对于早期版本的数据库,MAXEXTENTS的缺省值是255,这种情况下,某些较大的表就很容易达到了MAXEXTENTS的极限,这个时侯再插入数据,我们可能就会看到ORA-01631: Max # Extents (%s) Reached in TABLE %s.%s错误信息。这个时候就必须去加大MAXEXTENTS参数了。
了解了表和SEGMENT,下面我们来看看表的内部,我们知道表中的数据是存储在BLOCK里的,那么BLOCK的结构是什么样的呢?






实际上在一个BLOCK里,头部是BLOCK的HEADER,存储了一些数据块的信息、SCN、事务槽等信息。尾部的4个字节是块尾,块尾的目的是和块头的数据进行校验,确保这个数据块是一致的。块头和块尾中间的部分就是存储数据的。表中的数据是从数据块的底部开始存储的。比如我们在某个BLOCK中存储了3条记录,那么第一条记录的尾部正好和块尾相接,存储在BLOCK的最后,第三条记录存储在靠近块头的地方,前面就是这个块的空闲空间。随着数据块中数据的增长,数据区域逐渐接近块头的位置,也就是块中空闲的部分越来越少。如果这个块的空闲空间不足以插入一条新纪录了,那么就会寻找别的可以插入数据的块,如果所有的数据块都已经满了,那么就会扩展一个新的EXTENT。
现在我们的表中都设计了大量的VARCHAR字段,VARCHAR字段使用起来十分灵活,而且不会浪费空间,所以很好用。不过VARCHAR字段的使用也给BLOCK中的数据重组带来了麻烦。比如说我们在一张包含VARCHAR字段的表中插入一条数据的时候,如果某个字段首先我们插入了1个字节,而后来我们通过UPDATE将这个字段的值修改为200个字节,那么这条记录就需要重组,从而导致整个BLOCK进行重组。而如果这个时候我们修改的这条记录所在的BLOCK已经没有200个空闲的字节了,那么这条记录修改后就无法存储在这个BLOCK里了,Oracle在处理这种情况的时候,会把这条记录整个迁移到另外一个存在足够空闲空间的数据块中,而在原来记录的地方登记一个指向新位置的指针,这种情况就是我常说的行链。行链的产生,会加大系统的开销,影响对数据访问的性能。

今天就先说到这,明天在总结表的分类及每种表的特点和适用环境




----end------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: