数据库表(9i&10g学习)

来源:互联网 发布:js中的insertArray 编辑:程序博客网 时间:2024/06/13 16:55

Oracle中的段(segment)是占用磁盘上存储空间的一个对象。尽管有多种类型,不过最常见的段类型如下:
 聚簇(cluster):这种段类型能存储表。有两种类型的聚簇:B*树聚簇和散列聚簇。聚簇通常用于存储多个表上的相关数据,将其“预联结”存储到同一个数据库块上;还可以用于存储一个表的相关信息。“聚簇”这个词是指这个段能把相关的信息物理的聚在一起。
表(table):表段保存一个数据库表的数据,这可能是最常用的段类型,通常与索引段联合使用。
q表分区(table partition)或子分区(subpartition):这种段类型用于分区,与表段很相似。分区表由一个或多个分区段(table partition segment)组成,组合分区表则由一个或多个表子分区段(table subpartition segment)组成。
索引(index):这种段类型可以保存索引结构。
索引分区(index partition):类似与表分区,这种段类型包含一个索引的某个片。分区索引由一个或多个索引分区段(index partition segment)组成。
 Lob分 区(lob partition)、lob子分区(lob subpartition)、lob索引(lobindex)和lob段(lobsegment):lobindex和lobsegment段保存大对象 (large object或LOB)的结构。对包含LOB的表分区时,lobsegment也会分区,lob分区段(lob partition segment)正是用于此。有意思的是,并没有一种lobindex分区段(lobindex partition segment)类型——不论出于什么原因,Oracle将分区lobindex标记为一个索引分区(有人很奇怪为什么要另外给lobindex取一个特 殊的名字!)。
嵌套表(nested table):这是为嵌套表指定的段类型,它是主/明细关系中一种特殊类型的“子”表。
回滚段(rollback)和undo段:undo数据就存储在这里。回滚段是DBA手动创建的段。 undo段由Oracle自动创建和管理。

一个表可以是一个段,索引有可能是一个段,我们可以把一个索引划分到不同的段中。所以,索引对象本身只是一个定 义,而不是一个物理段,索引可能由多个索引分区组成,而每个索引分区(index partition)是一个段。表可能是一个段,也可能不是。由于同样的原因,由于表分区,一个表可以有多个表段:或者可以在一个称为聚簇的段中创建一个 表,此时这个表可能与其他表同在一个聚簇段中。不过,最常见的情况是,表是一个段,索引也是一个段。

段空间管理

手 动段空间管理(Manual Segment Space Management):由你设置FREELISTS、FREELIST GROUPS、PCTUSED和其他参数来控制如何分配、使用和重用段中的空间。在这一章中我会把这种空间管理方法称为MSSM。
自动段空间管理(Automatic Segment Space Management, ASSM):你只需控制与空间使用相关的一个参数:PCTFREE。创建段时也可以接受其他参数,但是这些参数将被忽略。

MSSM是Oracle的遗留实现。它已经存在多年,许多版本都支持MSSM。ASSM则在Oracle 9i Release 1中 才首次引入。原先用于控制空间分配和提供高并发性的参数数不胜数,并且需要对这些参数进行调整,人们不希望还要这么做,这正是设计ASSM的出发点

高水位线

HWM很重要,因为Oracle在全面扫描段时会扫描HWM之下的所有块,即使其中不包含任何数据这会影响全面扫描的性能,特别是当HWM之下的大多数块都为空时。要查看这种情况,只需创建一个有1,000,000行的表(或者创建其他有大量行的表),然后对这个表执行一个SELECT COUNT(*)。 下面再删除(DELETE)这个表中的每一行,你会发现尽管SELECT COUNT(*)统计出0行,但是它与统计出1,000,000所花的时间一样长(如果需要完成块清除,时间可能还会更长)。这是因为Oracle在忙于读取HWM之下的所有块,查看其中是否包含数据。如果对这个表使用TRUNCATE而不是删除其中的每一行,你可以比较 一下结果有什么不同。TRUNCATE会把表的HWM重置回“0”,还会截除表上的相关索引。由于以上原因,如果你打算删除表中的所有行,就应该选择使用 TRUNCATE(如果可以使用的话)。

低HWM

为什么有了HWM还又有一个低HWM呢,这个是因为自动段空间管理的特性造成的。在手段段空间管理中,当数据插入以后,如果是插入到新的数据块中,数据块就会被自动格式化等待数据访问。而在自动段空间管理中,数据插入到新的数据块以后,数据块并没有被格式化,而是在第一次访问这个数据块的时候才格式化这个块。所以我们又需要一条水位线,用来标示已经被格式化的块。这条水位线就叫做低HWM。一般来说,低HWM肯定是低于等于HWM的

FREELISTS:使用MSSM表空间时,Oracle会在自由列表(freelist)中为有自由空间的对象维护HWM一些的块。注意 freelists组和freelist组在ASSM表空间中根本就没有;仅MSSM表空间使用这个技术。

PCTFREE和PCTUSED:一 般而言,PCTFREE参数用来告诉Oracle应该在块上保留多少空间来完成将来的更新。默认情况下,这个值是10%。如果自由空间的百分比高于 PCTFREE中的指定值,这个块就认为是“自由的”。PCTUSED则告诉Oracle当前不“自由”的一个块上自由空间百分比需要达到多大才能使它再 次变为自由的。默认值是40%。

实际上PCTUSED的含义是:如果块上不自由的空间到达或小于PCTUSED参数指定的百分比时,这个块将重新变为自由,如倘若PCTUSED为40%,那么块上不自由的空间小于40%时,即自由空间达到60%时,这个块就重新变为自由

对 于不同的表类型,PCTFREE和PCTUSED的实现有所不同。对于某些表类型,这两个参数都要使用,而另外一些表类型只使用PCTFREE,而且对于这些表类型,仅当创建对象时才会使用PCTFREE。IOT在创建时可以使用PCTFREE在表中预览空间来完成将来的更新,但是在其他方面并不使用 PCTFREE,例如,PCTFREE不用于决定何时停止向一个给定块中插入行。

根 据你使用的是ASSM表空间还是MSSM表空间,这两个参数的实际作用会有所不同

使用MSSM时,这些参数设置控制着块何时放入freelist中,以 及何时从freelist中取出。如果使用默认值:PCTFREE为10,PCTUSED为40,那么在块到达90%满之前(有10%以上的自由空间), 这个块会一直在freelist上。一旦到90%,就会从freelist中取出,而且直到块上的自由空间超过了块的60%时,才会重新回到 freelist上,在此之前,这个块一直不在freelist上。

使用ASSM时,PCTFREE仍然会限制能否将一个新行插入到一个块中,但是它不会控制一个块是否在freelist上,因为ASSM根本不使用freelist。在ASSM中,PCTUSED将被忽略。

PCTFREE有3 种设置:太高、太低好刚好

如果把块的PCTFREE设置得过高,就会浪费空间。如果把PCTFREE设置为50%,而你从未更新数据,那么每个块都会浪 费50%的空间。不过,在另一个表上,50%可能非常合理。如果行初始很小,现在想将行的大小加倍,但是倘若PCTFREE设置得太小,更新行时就会导致 行迁移。

高PCTFREE,低PCTUSED:如果你插入了将要更新的大量数据,而且这些更新会频繁地增加行的大小,此时就适合采用这种设置。这种设置在插入后会在块上预留大量的空间(高PCTFREE),并使得将块放回到freelist之前必须几乎为空(低PCTUSED)。

低PCTFREE,高PCTUSED:如果你只想对表完成INSERT或DELETE,或者如果你确实要完成UPDATE,但UPDATE只是缩小行的大小,此时这种设置就很适合

行迁移

行迁移(row migration)是指由于某一行变得太大,无法再与其余的行一同放在创建这一行的块中(块中已经放不下这一行),这就要求这一行离开原来的块。迁移行(migrated row)就是这一行从最初所插入的块上移到另外的某个块上。行迁移 只会影响性能。如果你通过一个索引来读这一行,索引会指向原来的块,那个块再指向这个新块。要得到具体的行数据,一般并不是执行两个左右的I/O就可以得 到行数据。单独来看,这不是大问题,甚至根本注意不到。不过,如果这种行所占的比例相当大,而且有大量用户在访问这些行,你就会注意到这种副作用了。访问 这些数据的速度开始变慢(额外的I/O以及与I/O相关的闩定都会增加访问时间),缓冲区缓存的效率开始下降(需要缓存两个块,而如果行没有迁移就只需要 缓存一个块),另外表的大小和复杂性都有所增加。由于这些原因,你可能不希望迁移行

堆组织表
应用中99%(或者更多)的情况下使用的可能都是堆组织表,执行 CREATE TABLE语句时,默认得到的表类型就是堆组织表。如果你想要任何其他类型的表结构,就需要在CREATE语句本身中指定它。一般来讲,数据库表本质上是无序的数据集合,应该把堆组织表看作一个很大的无序行集合
CREATE TABLE技巧:尽可能简单地创建表,例如:
create table t ( x int primary key,y date, z clob)
索引组织表
索引组织表(index organized table,IOT) 就是存储在一个索引结构中的表。存储在堆中的表是无组织的(也就是说,只要有可用的空间,数据可以放在任何地方),IOT中的数据则按主键存储和排序。对你的应用来说,IOT表现得与一个“常规”表并无二致;还是要使用SQL正常地访问这些表。IOT对信息获取、空间应用和OLAP应用特别有用。
如 果你想保证数据存储在某个位置上,或者希望数据以某种特定的顺序物理存储,IOT就是一种合适的结构
适用场景:

1:表的大小与主键索引的大小相当(实际上,主键索引更大,因为它物理地存储了所指向的行 的rowid;而表中并不存储rowid,表中的行ID是推断出来的)
2:另一个适于使用IOT的实现是代码查找表。例如,可能要从ZIP_CODE查找STATE。此时可以不要堆表,而只使用IOT本身。如果你只会通过主键来访问一个表,这个表就非常适合实现为IOT
索引聚簇表:
利用聚簇表可以物理地“预联结”数据。使用聚簇可以把多个表上的相关数据存储在同一个数据库块上。聚簇有助于完成总是把数据联结在一起或者访问相关数据集(例如,部门10中的每一个人)的读密集型操作。
聚簇表可以减少Oracle必须缓存的块数,从而提供缓存区缓存的效率。不好的一面是,除非你能正确地计算出SIZE参数设置,否则聚簇在空间利用方面可能效率低下,而且可能会使有大量DML的操作变慢。
散列聚簇表(Hash clustered table)
 在概念上与前面介绍的索引聚簇表非常相似,只有一个主要区别:聚簇键索引被一个散列函数所取代。表中的数据就是索引;这里没有物理索引。Oracle会取得一行的键值,使用每个内部函数或者你提供的每个函数对其计算散列,然后使用这个散列值得出数据应该在磁盘上的哪个位置。不过,使用散列算法来定位数据有 一个副作用,如果不向表增加一个传统的索引,将无法对散列聚簇中的表完成区间扫描。在一个索引聚簇中,如果有以下查询:
select * from emp where deptno between 10 and 20
它就能利用聚簇键索引来找到这些行。在一个散列聚簇中,这个查询会导致一个全表扫描,除非DEPTNO列上已经有一个索引。如果没有使用一个支持区间扫描的索引,就只能在散列键上完成精确搜索(包括列表和子查询)
散列聚簇一开始就要分配空间。Oracle根据你的HASHKEYS和SIZE来计算HASHKEYS/trunc(blocksize/SIZE),立即分配空间,并完成格式化,一旦将第一个表放入这个聚簇中,任何全面扫描都会命中每一个已分配的块。在这方面,它与其他的所有表都不同。
q 散列聚簇中的HASHKEY数是固定大小的。除非重新聚簇,否则不能改变散列表的大小。这并不会限制聚簇中能存储的数据量,它只是限制了能为这个聚簇生成的惟一散列键的个数。如果HASHKEY值设置得太低,可能因为无意的散列冲突影响性能。
q 不 能在聚簇键上完成区间扫描。诸如WHERE cluster_key BETWEEN 50 AND 60谓词条件不能使用散列算法。介于50~60之间的可能值有无限多个,服务器必须生成所有可能的值,并分别计算散列,来查看相应位置是否有数据。这是不 可能的。如果你在一个聚簇键上使用区间扫描,而且没有使用传统索引,实际上会全面扫描这个聚簇。
散列聚簇适用于以下情况:
1:你很清楚表中会有多少行,或者你知道一个合理的上界
。HASHKEY和SIZE参数的大小要正确,这对于避免聚簇重建至关重要。与 获取操作相比,DML(特别是插入)很轻。这说明必须在数据获取的优化和新数据的创建之间有所权衡。有多少个插入算轻,对此没有定论,对某些人来说,每个 单位时间有100,000个插入就算轻,而在另一个人来看,可能每单位时间100个插入才算轻——这取决于具体的数据获取模式。更新不会引入严重的开销, 除非更新了HASHKEY(不过这可不是一个好主意,因为更新HASHKEY会导致行迁移)。
2:经常按HASHKEY值访问数据。例如,假如有一个零件表,并按零件号来访问这些零件。查找表特别适合采用散列聚簇。
有序散列聚簇表
有序散列聚簇是Oracle 10g中新增的。其中不仅有前面所述的散列聚簇的有关性质,还结合了IOT的一些性质。如果经常使用类似于以下的查询来获取数据,有序散列聚簇就最适合:
Select * From t Where KEY=:x Order by SORTED_COLUMN
有序散列聚簇具备散列聚簇在获取方面的所有特点,因为它能得到数据而不必遍历索引;另外有序散列聚簇还拥有IOT的许多特性,因为数据可以按你选择的 每个字段(键)有序地存储。当输入数据按排序字段(键)的顺序到达时,这种数据结构就能很好地工作。也就是说,在一段时间内,数据按某个给定键值的递增有 序顺序到达。股票信息就满足这个要求。每天晚上你会得到一个新文件,其中填满了股票代码、日期以及相关的信息(日期是排序键,股票代码是散列键)。你按排 序键顺序地接收好加载这些数据。对于股票代码ORCL,昨天的股票数据不会在今天之后才到达,你会先加载昨天的值,然后才是今天的值,之后是明天的值。如 果信息随机地到达(不按有序的顺序到来),插入过程中,这个数据结构很快就会受不了,因为必须移动大量的数据使得这些行在磁盘上物理有序。在这种情况下, 不建议采用有序散列聚簇(此时采用IOT可能很合适)。
使用这个结构时,应当考虑到散列聚簇同样的问题,另外还要考虑到一个约束条件,即数据应该按键值的有序顺序到达。
嵌套表
嵌 套表(nested table)是Oracle对象关系扩展的一部分。嵌套表是Oracle中的两种集合类型之一,它与关系模型中传统的“父/子表对”里的子表很相似。复杂,很少用到,暂不讨论
临时表
临 时表(Temporary table)用于保存事务或会话期间的中间结果集。临时表中保存的数据只对当前会话可见,所有会话都看不到其他会话的数据
Oracle的临时表是“静态”定义的。每个数据库只创建一次临时表,而不是为数据库中的每个存储 过程都创建一次。在Oracle中,临时表一定存在,它们作为对象放在数据字典中
不要在运行时在你的存储过程中创建表。这不是Oracle中使用临时表的正确做法。DDL是一种代价昂贵的操作:你要全力避免在运行时执行这种操作。一个应用的临时表应该在应用安装期间创建,绝对不要在运行时创建。
临时表可以有永久表的许多属性。它们可以有触发器、检查约束、索引等。但永久表的某些特性在临时表中并不支持,这包括:
不能有引用完整性约束。临时表不能作为外键的目标,也不能在临时表中定义外键。
不能有NESTED TABLE类型的列。在Oracle 9i及以前版本中,VARRAY类型的列也不允许;不过Oracle 10g中去掉了这个限制。
不能是IOT。
不能在任何类型的聚簇中。
 不能分区。
不能通过ANALYZE表命令生成统计信息。
在 所有数据库中,临时表的缺点之一是优化器不能正常地得到临时表的真实统计。使用基于代价的优化器(cost-based optimizer,CBO)时,有效的统计对于优化器的成败至关重要。如果没有统计信息,优化器就只能对数据的分布、数据量以及索引的选择性作出猜测。 如果这些猜测是错的,为查询生成的查询计划(大量使用临时表)可能就不是最优的。在许多情况下,正确的解决方案是根本不使用临时表,而是使用一个 INLINE VIEW(要看INLINE VIEW的例子,可以查看前面运行的SELECT,它就有两个内联视图)。采用这种方式,Oracle可以访问一个表的所有相关统计信息,而且得出一个最 优计划
不要在运行时在你的存储过程中创建表。这不是Oracle中使用临时表的正确做法。DDL是一种代价昂贵的操作:你要全力避免在运行时执行这种操作。一个应用的临时表应该在应用安装期间创建,绝对不要在运行时创建。
对象表  复杂,很少用到,暂不讨论


原创粉丝点击