Oracle的存储结构关系
oracle数据库的整体结构
数据库的结构关系
其实,我前面一篇讲表空间的时候就介绍了数据库的结构,只是那个图只是简单的层次关系,这张图片看上去挺封复杂的,只要关注几个概念就行了。
Database(数据库) :数据库是按照数据结构来组织、存储和管理数据的仓库。
Tablespaces(表空间) :表空间是数据库的逻辑划分,一个表空间只能属于一个数据库。所有的数据库对象都存放在指定的表空间中。但主要存放的对象是表, 所以称作表空间。
Segments (段): 段是表空间的重要组织结构,段是指占用数据文件空间的通称,或数据库对象使用的空间的集合;段可以有表段、索引段、回滚段、临时段和高速缓存段等。
extents (盘区):是数据库存储空间分配的一个逻辑单位,它由连续数据块所组成。第一个段是由一个或多个盘区组成。当一段中间所有空间已完全使用,oracle为该段分配一个新的范围。
Data Block (数据块):是oralce 管理数据文件中存储空间的单位,为数据库使用的I/O的最小单位,其大小可不同于操作系统的标准I/O块大小。
(Storage Clause Precedence)存储规范优先
Oracle 在存储控制上可以分为三个方式。oracle缺省级别、表空间级别、段级别,可以理解中央、省级、县级。从中央到地方的法规条例。比如为了发展经济,对于招商引资的规范。中央规定可以实行招商引资,某省比较穷,为了吸引投资商,规定降低企业所得税。某县为了吸引资源,可以规定对于投资商土地免费使用5年,不征收土地使用税。那么某投资商来本县后首先适用县级规定。
具体规定:
1、不管你在哪个层面上修改存储方式,修改的参数是对未来要分配的存储extents (盘区)起作用。
2、一些参数只能在指定的级别上进行修改。有些参数只能表空间级别设置,有些参数只能在段级别设置。
Types of segments (段的类型)
因为关于表空间的一些基本知识我在另一节里做过专门介绍,这里我们认识一下段都有哪些常见类型。
Table :
对于一个只有几百条几千条数据,一个学校的学生成绩表,那么一张表就是一个segments 。
Table partition :
如果一张表非常大,里面存储了几千万条、上亿条记录,那么对这一张表进行操作,效率就非常低了。分区表是将大表的数据分成称为分区的许多小的子集。假如一张表是存放中国13亿人口信息的表,那么这么多条记录是有规律的,可以基于某一个字段将其分开。那么可以根据省级行政区可以划分34个分区,每个分区实际上就是一个独立的表,但在逻辑上这些分区又同属于一张表。
如果一张表是普通的表,只点一个segments;如果一张表是partition的表,可能占多个segments。
Cluster :
Oracle中普通的表称为堆表(heap table),堆表中的数据是无序存放的,往往在使用一段时间后,数据就变得非常无序。如下图所示,索引中相同的key对应的数据存放在不同的block中,这时,如果要通过索引查询某个key的数据,就需要访问很多不同的block,代价非常高。
我们发现很多表与表,他们的数据有相关性,因为我们访问一个表里的数据,往往要访问另一些表里的数据。我们可以把这些数据物理上存储在一块。
Index
索引是与表和聚集相关的一种选择结构,就当于我们一本书的目录,可以快快速的定位某章某节的页数。索引可以建立在一个表的一列或多列上,那就可以大大提高对表的查询。那么一个index也可能会占一个多个segments 。
Index-organized table :
索引组织表(IOT),就是存储在一个索引结果中的表。存储在堆中的表是无组织的(也就是说,只要有可用的空间,数据可放在任何地方),IOT中 暗则按主键存储和排序。对你的应用来说,IOT表和一个“常规”表并无差别。使用堆组织表时,我们必须为表和表主键上的索引分别留出空间。而IOT不存在主键的空间开销,因为所引就是数据,数据就是所引。
IOT带来的好处不仅节约磁盘空间的占用,更重要的是大幅度降低了I/O,减少了访问缓冲区缓存(尽管从缓冲区缓存获取数据比硬盘要快得多,但缓冲区缓存并不是免费,而且也绝不是廉价的。第个缓冲区缓存获取都需要缓冲区缓存的多个闩,而闩是串行化设备,会限制应用的扩展能力)
Index partition
对于table有partition ,那么对一个大的index有也partition 。
分区所引可以分为全局分区索引与本地分区索引,其中本地索引又可以分为本地前缀索引和本地非前缀索引。
本地索引的分区和其对应的表分区数量相等,因此每个表分区都对应着相应的索引分区。使用本地索引,不需要指定分区范围因为索引对于表而言是本地的,当本地索引创建时,Oracle会自动为表中的每个分区创建独立的索引分区。
全局索引以整个表的数据为对象建立索引,索引分区中的索引条目既可能是基于相同的键值但是来自不同的分区,也可能是多个不同键值的组合。 全局索引既允许索引分区的键值和表分区键值相同,也可以不相同。全局索引和表之间没有直接的联系,这一点和本地索引不同。
Undo segment
回滚段用于存放数据修改之前的值(包括数据修改之前的位置和值)。回滚段的头部包含正在使用的该回滚段事务的信息。一个事务只能使用一个回滚段来存放它的回滚信息,而一个回滚段可以存放多个事务的回滚信息。
Temporary segment
当Oracle处理一个查询时,经常需要为 SQL语句的解析与执行的中间结果(intermediate stage)准备临时空间。Oracle会自动地分配被称为临时段(temporary segment)的磁盘空间。例如,Oracle在进行排序操作时就需要使用临时段。当排序操作可以在内存中执行,或Oracle设法利用索引就执行时,就不必创建临时段。
LOB segment
Large object (LOB) 大大的对象,我们知道数据库不但可以存数据,有些可以存储视频声音图片等文件,对于这种类型的文件一个大小几MB,几十MB很正常。当然,有些数据库是不支持LOB数据块的,可以在表里存一个指针,来指向某个文件下的视频声音文件。
Nested table
嵌套表,表中表,和LOB思想很类似,就是在表里存一个指针,指针指向另外一张表。
Bootstrap segment
关于引导段,暂时没找到相关解释。^_^
Extent alloc & dealloc (盘区分配与释放)
盘区是段下面的一个存储单位,一个盘区在物理上是一段连续的数据块。
一个数据文件有一个文件头,点用了若干个数据块,这这个文件头里记录着盘区的分配与释放的信息。在这个文件中有些盘区是被使用的,有些盘区是空闲的。
什么时候创建盘区:
创建
扩展
改变(改大)
什么时候释放盘区:
删除
改变(改小)
Database Block(数据库块)
最小单位的输入/输出
数据块由操作系统中的一个或多个块组成
数据块是表空间的基本单位
DB_BLOCK_SIZE 文件来表示缺省块的大小
查看oracle 块的大小:
*.db_block_size=8192 (8KB)
在早期的数据库中,oracle只支持一种数据块的大小。从9i版本支持了改变大小的设置。但也不是任用户随便改动的,规定范围在2KB到32KB之间,必须是倍数增加的,也就是2KB\4KB\8KB\16KB\32KB 五种大小。
需要注意的是,块大小的设置是在数据库创建时候设置的,一旦设置好是不可更改的。类似于我们磁盘的存储格式,FAT16、FAT32、NTFS.... ,要想改变存储格式只能数数据全部格式化掉。
Hearder : 块头记录一些控制信息,帮助oracle定位这个块,块与块之间的串联信息。
Free space :处于重现状态的这空间。
Data :已经写入数据的空间。数据存放数据的方式是自底往上的,就像现实中的一个箱子。
Orcale 是如何管理数据的存储的
High-Water Mark
对一一个新建立的表,表中包含很多数据块,water mark 原始指向表中的第一个数据块。
water mark随着插入的数据“向前”移动。当把插入的数据删除掉一些,water mark 并不会“向后”移动。也就是water mark 的位置表示历史的最高水位。
那么我们要想插入一些数据时,oralce是按什么样的规则输选择插入位置呢?
首先会先查找灰色的,灰色部分表示就已经插入数据的块,但这些块并不是已经被完全占满了,有些或多或少的都会留下一些空间,关于留空间的规则,后面细说。如果插入一个很小的数据,灰色被占的数据块中可以完全插入的,就会被插在这一部分。
如果数据比较大,查找了所有被占用块都无法插入,那么将会选择“曾经”插入过数据的空白块进行插入,也就是上图浅灰色部分。
如果数据非常大,曾经插入数据的空白块都无法插入,那么只好动用从未被插入过数据的空白块进行插入。当然water mark 也就会“向前”移动。
OK下面就来具体分析,每个数据块,是否允许插入数据的规则。
块头(数据块的头)不在百分比的范围内,当剩余空间大于20%的时候,那这个块就是纳入freelist中,当我要插入一条数据时,freelist是会扫描这个块的,检查其它是否可以存放要插入的数据。当小于20%的这间时,说明这个块已经满了,会从freelist中去掉,插入数据时不作为扫描的对象。
一个小于20%空闲的块会从freelist上摘除,那么一个块在什么情况下会被重新挂到freelist上呢?对于一个已经从freelist上摘除的块,可以能由于删除更新操作,其空间会得到释放,当占用空间小于40%时,也就是空闲空间大于60%时,这个块被有认为是空间的块又会被重现挂到freelist上。